How to build a portfolio website with React & Tailwind CSS

Amrin - Jan 14 '23 - - Dev Community

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.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .