DEV Community

Cover image for How to build a portfolio website with React & Tailwind CSS
Amrin
Amrin

Posted on • Edited on

How to build a portfolio website with React & Tailwind CSS

Every developer must have a portfolio website to showoff their skills and projects.

If you prefer video tutorial you can watch it here:

In this article I’ll show you how to do exactly that.
We will build portfolio website with React.js and Tailwind CSS.

You may ask It's just a landing page?
Why not build it with vanilla CSS and Html.
The reason I choose React and Tailwind to build this project is because I’ll integrate a blog API into this project. I’ll share that in a future article.

Prerequisite:

To follow along you don’t need to be a pro at anything, all you need is just the fundamentals.

  1. Basic understanding of vanilla CSS
  2. Basic understanding of JavaScript.
  3. Fundamental of React and Tailwind.

Now that you know what you need, let’s start building.

Setup

To build the project first we need to setup a React.js and Tailwind CSS project. You can do that easily using the Tailwind docs.
Follow these instructions from tailwind docs to setup the project.

Setup React and Tailwind Project

I’ll wait for you to setup the project.

You are done!

let’s move on to the next step.

The Components

Before we start we need to know little about the structure of the project.

Because it’s React we will be breaking down the websites into tiny components.

We’ll have 6 components:

  1. Header
  2. Hero
  3. About
  4. Projects
  5. Blog
  6. Footer

Note: all these components will be inside the components folder under the src folder. And all the component will be imported in the App.js file.

Like this:

import "./App.css";
import Header from "./components/Header";
import Hero from "./components/Hero";
import About from "./components/About";
import Projects from "./components/Projects";
import Blog from "./components/Blog";
import Contact from "./components/Contact";
import Footer from "./components/Footer";

function App() {
  return (
    <>
      <Header />
      <Hero />
      <About />
      <Projects />
      <Blog />
      <Contact />
      <Footer />
    </>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

#1. Header

The have a responsive mobile menu with a toggle button, and a desktop menu.

We will use react useState hook to implement the toggle effect. And for the icons we’ll use the React Icons library.


import React, { useState } from "react";
import { AiOutlineMenu, AiOutlineClose } from "react-icons/ai";

const Header = () => {
  const [toggle, setToggle] = useState(false);

  const handleToggle = () => setToggle(!toggle);

  return (
    <header className="flex justify-between px-5 py-2 bg-primary text-white fixed w-full z-10">
      <a href="/" className="logo text-2xl font-bold text-accent">
        Amrin
      </a>

      {/* Desktop Nav */}
      <nav className="hidden md:block">
        <ul className="flex">
          <li>
            <a href="/#about">About</a>
          </li>
          <li>
            <a href="/#projects">Projects</a>
          </li>
          <li>
            <a href="/#blog">Blog</a>
          </li>
          <li>
            <a href="/#contact">Contact</a>
          </li>
          <li>
            <a href="#resume -link" target="_blank" without rel="noreferrer">
              Resume
            </a>
          </li>
        </ul>
      </nav>

      {/* Mobile Nav */}
      <nav
        className={!toggle ? "mobile-nav left-[-100%]" : "mobile-nav left-0"}
      >
        <ul className="flex flex-col">
          <li>
            <a href="/#about">About</a>
          </li>
          <li>
            <a href="/#projects">Projects</a>
          </li>
          <li>
            <a href="/#blog">Blog</a>
          </li>
          <li>
            <a href="/#contact">Contact</a>
          </li>
          <li>
            <a href="/#resume">Resume</a>
          </li>
        </ul>
      </nav>

      {/* Toggle button */}
      <button onClick={handleToggle} className="block md:hidden">
        {!toggle ? <AiOutlineMenu size={30} /> : <AiOutlineClose size={30} />}
      </button>
    </header>
  );
};

export default Header;
Enter fullscreen mode Exit fullscreen mode

Because we have a custom color pallet, I decided to create some utility classes for the colors.

/* color */
.bg-primary {
    background: #0F172A;
}

.bg-secondery {
    background: #1E293B;
}

.bg-accent {
    background: #7477FF;
}

.text-accent {
    color: #7477FF;
} 
Enter fullscreen mode Exit fullscreen mode

As we styled the mobile nav with tailwind, it was getting really messy and repetitive. So, I decided to extract the classes and put them on a custom class called .mobile-nav on Style.css file, like this

.mobile-nav {
    @apply block md:hidden fixed top-10 py-2 w-full h-full bg-gray-900 duration-500;
} 
Enter fullscreen mode Exit fullscreen mode

Also to style the a tags inside nav, we used some custom css. Otherwise we would repeat ourselves a lot.

nav li a {
    @apply px-4 py-5 text-lg;
}

nav li a:hover {
    color: #7477FF;
}
Enter fullscreen mode Exit fullscreen mode

Now that we are done with the nav let’s move on to the hero section.

#2. Hero

The hero consists of two sections, one is the hero-info and the other is hero-img.

I’ve used an illustration on the hero-img you can use your picture if you prefer.

import React from "react";
import HeroImg from "../assets/hero-img.png";

import {
  AiOutlineTwitter,
  AiOutlineYoutube,
  AiOutlineFacebook,
} from "react-icons/ai";

const Hero = () => {
  return (
    <section className="bg-primary px-5 text-white py-32">
      <div className="container mx-auto grid md:grid-cols-2 items-center justify-center md:justify-between">
        <div className="hero-info pb-5 md:pb-0">
          <h1 className="text-4xl lg:text-6xl">
            Hi, <br />I am <span className="text-accent">a</span>mrin <br />
            Frontend Developer
          </h1>

          <p className="py-5">
            I am proficient in JavaScript, React.js and Tailwind CSS
          </p>

          <div className="flex py-5 ">
            <a
              href="https://twitter.com/CoderAmrin"
              className="pr-4 inline-block text-accent hover:text-white"
            >
              {" "}
              <AiOutlineTwitter size={40} />{" "}
            </a>
            <a
              href="https://www.youtube.com/@coderamrin"
              className="pr-4 inline-block text-accent hover:text-white"
            >
              {" "}
              <AiOutlineYoutube size={40} />{" "}
            </a>
            <a
              href="https://www.facebook.com/CoderAmrin/"
              className="pr-4 inline-block text-accent hover:text-white"
            >
              {" "}
              <AiOutlineFacebook size={40} />{" "}
            </a>
          </div>

          <a
            href="/#projects"
            className=" btn bg-accent  border-2 border-[#7477FF] text-white px-6 py-3 hover:bg-transparent"
          >
            See Projects
          </a>
        </div>

        <div className="hero-img">
          <img
            src={HeroImg}
            alt="coding illustration"
            className="lgw-[80%] ml-auto"
          />
        </div>
      </div>
    </section>
  );
};

export default Hero;
Enter fullscreen mode Exit fullscreen mode

To style the hero title, we’ve used a custom font and added some custom styling.

Note: you’ll need to add this font on the index.html of your project. It’s a free google font.

/* hero */
h1 {
    font-family: 'Pacifico', cursive;
    line-height: 1.5 !important;
}
Enter fullscreen mode Exit fullscreen mode

#3. About

The about section consists of two parts just like the hero section.
First section will have all about you, what skills you have and what do you do. And the other section is about-img. It’s an illustration of a person coding.

Note: All the images are in the src/assets directory.

import React from "react";
import AboutImg from "../assets/about-img.png";

const About = () => {
  return (
    <section className="bg-secondery text-white px-5 py-32" id="about">
      <div className="container mx-auto grid md:grid-cols-2 items-center justify-center md:justify-between">
        <div className="about-info">
          <h2 className="text-4xl font-bold mb-5 border-b-[5px] w-[180px] border-indigo-600 pb-2">
            About Me
          </h2>

          <p className="pb-5">
            Hi, My Name Is Rohima Akther everyone calls me Amrin. I am a
            Frontend Developer. I build beautifull websites with React and
            Tailwind CSS.
          </p>
          <p className="pb-5">
            I am proficient in Frontend skills like React.js, Redux, Redux Tool
            Kit, Axios, Tailwind CSS, SaSS, Css3 and many more.
          </p>

          <p>In backend I know Node.js, Express.js, MongoDB, and Mongoose</p>

          <p>
            In my spare time I create YouTube videos and write blogs on my Blog.
            Where I talk about programming theory and build various projects.
          </p>
        </div>

        <div className="about-img">
          <img
            src={AboutImg}
            alt="coding illustration"
            className="lgw-[80%] md:ml-auto"
          />
        </div>
      </div>
    </section>
  );
};

export default About;
Enter fullscreen mode Exit fullscreen mode

To style this section we haven’t used any other custom css other than the color classes.

#4. Project

The project section is a little bit complex. First we’ve got all the projects in an array, so that we don’t have to repeat ourselves. With this array of projects we now can easily map through and render the project item.

const projects = [
    {
      img: devlog,
      title: "devlog",
      desc: " A multi author blog. Built with Node.js, MongoDB, React, Redux and Tailwind CSS ",
      live: "https://devlogg.onrender.com/",
      code: "https://github.com/Coderamrin/devlog",
    },
    {
      img: uilogs,
      title: "uilogs",
      desc: "Free website template directory for SaaS and Degital Agency. Built with Bootstrap, JQuery and JavaScript",
      live: "https://uilogs.xyz/",
      code: "https://github.com/Coderamrin/html-templates",
    },
    {
      img: cssProjects,
      title: "css projects",
      desc: "Frontend Mentor challange directory, solved with vanilla CSS",
      live: "https://build-10-css-projects.netlify.app/",
      code: "https://github.com/Coderamrin/build-10-css-projects",
    },
    {
      img: getInspirred,
      title: "get Inspirred",
      desc: "Quote search app. Used Quotable API for the quotes and React, Redux on the frontend",
      live: "https://get-inspirred.netlify.app/",
      code: "https://github.com/Coderamrin/get-inspired",
    },
  ]; 
Enter fullscreen mode Exit fullscreen mode

The rest of the product component is this.

import React from "react";
import cssProjects from "../assets/cssprojects.png";
import devlog from "../assets/devlog.png";
import getInspirred from "../assets/get-inspirred.png";
import uilogs from "../assets/uilogs.png";

const Projects = () => {
  const projects = [...];

  return (
    <section className="bg-primary text-white px-5 py-32" id="projects">
      <div className="container mx-auto grid md:grid-cols-2 items-center md:justify-between">
        <div className="about-info mb-5">
          <h2 className="text-4xl font-bold mb-5 border-b-[5px] w-[180px] border-indigo-600 pb-2">
            Projects
          </h2>

          <p className="pb-5">
            These are some of my best projects. I have built these with React,
            MERN and vanilla CSS. Check them out.
          </p>
        </div>

        <div className="about-img"></div>
      </div>

      <div className="projects container mx-auto grid md:grid-cols-3 gap-10">
        {projects.map((project, i) => {
          return (
            <div className="relative" key={i}>
              <img src={project.img} alt={project.title} />
              <div className="flex absolute left-0 right-0 top-[13px] bottom-0 mx-auto w-[90%] h-[90%]  bg-primary  opacity-0 duration-500 justify-center flex-col hover:opacity-100 ">
                <p className="py-5 text-center font-bold px-2 text-white">
                  {project.desc}
                </p>

                <div className="mx-auto">
                  <a
                    href={project.live}
                    className="px-5 py-2 bg-blue-500 hover:bg-blue-600 mr-5 font-bold"
                  >
                    Live
                  </a>
                  <a
                    href={project.code}
                    className="px-5 py-2 bg-blue-700 hover:bg-blue-800 font-bold"
                  >
                    Code
                  </a>
                </div>
              </div>
            </div>
          );
        })}
      </div>
    </section>
  );
};

export default Projects;
Enter fullscreen mode Exit fullscreen mode

#5. Blog

Now is the blog section. It almost like the projects section.

An array of blog items to map through and render the items.

All the other things are the same as the projects component.

import React from "react";

const Blog = () => {
  const post = [
    {
      img: "https://res.cloudinary.com/practicaldev/image/fetch/s--AuZFJnr6--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a8okx5rxzuh5fojibsy3.png",
      title: "How to build a counter app with JavaScript",
      url: "https://dev.to/coderamrin/how-to-build-a-counter-app-with-javascript-439p",
    },
    {
      img: "https://res.cloudinary.com/practicaldev/image/fetch/s--FsJZ6lhI--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gv7y2de8kalk9l0820ag.jpg",
      title: "JavaScript Ultimate Guide 02: The DOM",
      url: "https://dev.to/coderamrin/javascript-ultimate-guide-02-the-dom-3ho9",
    },
  ];

  return (
    <section className="bg-primary text-white px-5 py-32" id="blog">
      <div className="container mx-auto grid md:grid-cols-2 items-center md:justify-between">
        <div className="about-info mb-5">
          <h2 className="text-4xl font-bold mb-5 border-b-[5px] w-[100px] border-indigo-600 pb-2">
            Blogs
          </h2>

          <p className="pb-5">Some of my best blogs.</p>
        </div>

        <div></div>
      </div>

      <div className="projects container mx-auto grid md:grid-cols-2 gap-10">
        {post.map((item) => {
          return (
            <div>
              <img src={item.img} alt={item.title} />
              <h3 className="py-5 text-2xl">{item.title}</h3>
              <a
                href={item.url}
                className=" btn bg-accent  border-2 border-[#7477FF] text-white px-6 py-3 hover:bg-transparent"
              >
                Read More
              </a>
            </div>
          );
        })}
      </div>
    </section>
  );
};

export default Blog; 
Enter fullscreen mode Exit fullscreen mode

#6. Contact & Footer

Finally the contact section and the Footer section.

These sections are just some texts on the center of the div. No, fancy design.

#Contact

import React from "react";

const Contact = () => {
  return (
    <section className="bg-secondery px-5 py-32" id="contact">
      <div className="text-center md:w-[60%] mx-auto text-white">
        <h2 className="text-4xl font-bold mb-5 border-b-[5px] w-[200px] mx-auto border-indigo-600 pb-2">
          Contact Me
        </h2>
        <p>
          I am currently open for a fulltime Frontend Developer role. If you
          want to discuss about that feel free to email me or call me.
        </p>

        <p className="py-2">
          <span className="font-bold">Email:</span> coderamrin@gmail.com
        </p>
        <p className="py-2">
          <span className="font-bold">Phone:</span> +88 01624-890723
        </p>
      </div>
    </section>
  );
};

export default Contact;
Enter fullscreen mode Exit fullscreen mode

#Footer

import React from "react";

const Footer = () => {
  return <div className="py-4 text-center bg-primary text-white "> &copy; 2023 coderamrin all right reserved</div>;
};

export default Footer;
Enter fullscreen mode Exit fullscreen mode

Resources

Live: https://amrin.onrender.com/
Source Code: https://github.com/Coderamrin/portfolio

Conclusion

Now you have a portfolio. You can deploy it and show off your projects.

If you want you can add a blog to your portfolio and showoff your skills.

I’ll add dev api on this portfolio, if you want to see do the same follow me to notified when I post the article.

If you want to connect with me, you can find me at on Twitter and YouTube.

Thanks for reading to the end.

See you on a future article.

Top comments (17)

Collapse
 
jonrandy profile image
Jon Randy 🎖️ • Edited

Every developer must have a portfolio website to showoff their skills and projects

In reality, this simply isn't true. I've never had one, and all the best developers I've hired haven't had one. An interesting and active GitHub/GitLab/whatever account is a far better way to attract the interest of the hiring manager. A curated vanity project honestly tells them very little about the candidate. I've rejected a good number of candidates actually because of their portfolio sites. A portfolio site can catch the eye - sure, but if the hirer is doing their job correctly they will look past it for more honest detail.

Collapse
 
pixeleate profile image
Ulises Garcia • Edited

It really depends on the position you are applying for, if the company is looking for a FE Developer who is really good at CSS and have an eye for good design, having a good looking portfolio should be encouraged but optional, as an Interviewer myself I like to see a portfolios with links to source code in case is needed or possible, just to review the coding practices, also I know by my own experience that a lot of times developers work on private Github repos and they are not able to share what they have coded before, also all the code in their repos could be purely copy and paste and not actually their work, I will never reject any candidate because of not having one or the other, I will reject them for failing interviews, where I assess what matters to the specific role, if I fail at evaluating something, it will be completely my fault.

Collapse
 
coderamrin profile image
Amrin

wow!
I am applying for jobs lately. every job require a portfolio website to apply.
Appreciate your comment by the way. it's really insightful.

Collapse
 
jonrandy profile image
Jon Randy 🎖️

Bizarre - I have never once seen or written a job description for a developer that requires a portfolio - that is in over 25 years of professional experience

Collapse
 
joshaffiliate2022 profile image
Comment deleted
Collapse
 
coderamrin profile image
Amrin

do you want to learn Html, CSS?

Collapse
 
moazamdev profile image
Moazam Ali

A small suggestion from me, In the contact section your email and phone should be clickable which can be done by giving them links like 'mailto:coderamrin@gmail.com' and 'tel:+8801624890723' respectively.

Btw thanks for this detailed article.

Collapse
 
coderamrin profile image
Amrin

JazakAllah brother.
will add that soon. : )

Collapse
 
jagroop2001 profile image
Jagroop Singh

Tailwind CSS is such an Amazing thing !!

Collapse
 
coderamrin profile image
Amrin

yeah, it is.
After i've learned tailwind, now I build all my project with it.

Collapse
 
awaisalwaisy profile image
Alwaisy al-waisy

I am building a project in office. Also building portfolio site for client. You code repository surrely helpful for me.

Collapse
 
coderamrin profile image
Amrin

I am glad it was helpful Alwaisy :)

Collapse
 
johnkat_mj profile image
John Kat

Nice, thanks for sharing 🔥

Collapse
 
coderamrin profile image
Amrin

glad you liked it John.

Collapse
 
caominhdev profile image
Cao Quốc Minh

👍

Some comments may only be visible to logged-in visitors. Sign in to view all comments.