GSD

How to Build a React Portfolio Website

Posted by Taminoturoko Briggs on October 12, 2023

Post updated in 2024 by Deborah Emeni.

Portfolios are personal websites used to show our works, skills, accomplishments, experiences, and achievements in detail. As a developer, having one is essential for presenting evidence of our abilities to potential employers and clients when on a job hunt.

In this tutorial, you will learn how to build and deploy a portfolio website with React, Tailwind CSS, and ButterCMS.

Project requirements

To follow along with this tutorial, you need to have the following:

  • Basic knowledge of React and Tailwind CSS
  • Node.js and Git installed on your system
  • A code editor for writing and editing our code—I recommend using VS code, you can download it here.

What we'll be building

The portfolio will have sections showing our introduction, the skills we have acquired, and our most recent and best projects. You can find the code for this tutorial in this GitHub repo

Below is a GIF showing what we will build in the tutorial:

Portfolio landing page

Tools we need to build with React

Below are the tools and platforms we will use to build and deploy our portfolio website:

  • ButterCMS: This is a headless content management system (CMS) that we will be using to store and manage the content of different sections of the portfolio web page. To allow for frequent updates to the portfolio site, we will create components with ButterCMS that manage different portions of the portfolio. That will allow us to easily create, edit, and delete them from the CMS dashboard. You can try ButterCMS free for 14 days. Start your free trial to follow along with the tutorial!.
  • Tailwind CSS: Tailwind CSS is a utility-based CSS framework that enables developers to quickly build user interfaces. It provides the user with CSS classes that provide different CSS styles to easily customize an application. We will be using Tailwind CSS in our application to quickly build and design the portfolio web page.
  • React-scroll: React-scroll is a React.js library for handling scroll transitions in a React application. We will make use of React-scroll to smoothly scroll to sections of the web page when the corresponding navigation menu item is clicked upon.
  • React Icons: React Icons is a repository of numerous icons that include social icons, chat icons, and hero icons, among many others. We will make use of React Icons to provide the icons for the social media profiles, which will be displayed in our application.
  • Axios: Axios is a well-known library that is mostly used to send asynchronous HTTP queries to REST endpoints. When performing CRUD activities, this library comes in quite handy. Using this library, you can talk to the backend. In our application, we will use Axios to connect our CMS to our application through a fetch request which will return the content stored on our CMS.

How to set up the React environment

A starter GitHub repository has been created, which already includes the images and data required for this tutorial. This GitHub repository also contains dependencies and configurations for Tailwind CSS and other dependencies such as Axios, React Icons, and React Scroll.

Clone the Github repo by running the following in your terminal:

git clone -b starter https://github.com/Tammibriggs/portfolio-butterCMS.git

Afterward, navigate into the project directory with this command:

cd portfolio-butterCMS

Open the project in your code editor. If you're using Visual Studio Code, run the command code. in your terminal. You will see the following project folder structure:

.
└── PORTFOLIO-BUTTERCMS/
    ├── public
    ├── src
    ├── .gitignore
    ├── package-lock.json
    ├── package.json
    ├── postcss.config.js
    ├── README.md
    └── tailwind.config.js

Next, open your terminal in your project’s directory and run the following command to install the project’s dependencies:

npm install

Once all the project dependencies are installed, start the development server with this command:

npm start

Once you run that command, your project will be up and running on localhost, and you will be provided a URL. You can visit the URL in your browser to view the project:

Terminal showing localhost running the project.

Tutorial: How to build a React portfolio website step-by-step

React follows a component-based architecture where a large interface is decoupled into individual self-sustaining pieces called components. To build the portfolio, let’s start by creating multiple components.

Create a basic React component structure for each section

The portfolio will have a header with links to navigate to different sections of the page. It will include sections for “About,” “Skills,” “Works,” and a  “Contact Form.” Let’s start by creating and rendering the sections so you won’t have to return to this process.

In your src directory of the cloned project, create a folder called components and add the following files: Navbar.jsx, Home.jsx, About.jsx, Skills.jsx, Works.jsx, and Contact.jsx. The resulting folder structure in the src directory should be as follows:

.
└── src/
    ├── assets/
    │   ├── code2.png
    │   └── me.png
    ├── components/
    │   ├── About.jsx
    │   ├── Contact.jsx
    │   ├── Home.jsx
    │   ├── Navbar.jsx
    │   ├── Skills.jsx
    │   └── Works.jsx
    ├── App.js
    ├── index.css
    └── index.js

Next, create the About Component to define the content that will be displayed on the About Page. In your About.jsx file, add the following code:

import React from 'react'

function About() {
  return (
    <div>About</div> 
  )
}
export default About

In the About component, you are doing the following:

  • Importing the React library that is required for writing React components.

  • Defining a function called About(), which will serve as your React component that you will use as a reusable UI.

  • Defining what the About component will render on the screen in a return statement. For now, it simply returns a div element with an “About” text.

  • Exporting the About component to other parts of your React application.

Let’s apply the same approach to create the other components. In your Navbar.jsx file, add the following code that defines a `Navbar()` function with a `div,` which displays a “Navbar” text and exports your Navbar component:

import React from 'react'

function Navbar() {
  return (
    <div>Navbar</div> 
  )
}
export default Navbar

For your Home component, add the following code to your Home.jsx file. The code defines a Home() function with a div, which displays the text “Home” and exports your Home component:

import React from 'react'

function Home() {
  return (
    <div>Home</div> 
  )
}
export default Home

For your Skill component, add the following code to your Skills.jsx file. The code defines a Skills() function with a div, which displays a “Skills” text and exports your Skills component:

import React from 'react'

function Skills() {
  return (
    <div>Skills</div> 
  )
}
export default Skills

For your Works component, add the following code to your Works.jsx file. This code  defines a Works() function with a div, which displays a “Works” text and exports your Works component:

import React from 'react'

function Works() {
  return (
    <div>Works</div> 
  )
}
export default Works

For your Contact component, add the following code to your Contact.jsx file. This code defines a Contact() function with a div, which will display the text “Contact” and exports your Contact component:

import React from 'react'

function Contact() {
  return (
    <div>Contact</div> 
  )
}
export default Contact

Rendering all the created components

To ensure that React displays all the components you created, you’ll need to include each of the components in your App.js file. To do this, you’ll need to modify your App.js file with the following code:

import About from './components/About';
import Contact from './components/Contact';
import Home from './components/Home';
import Navbar from './components/Navbar';
import Skills from './components/Skills';
import Works from './components/Works';

function App() {
  return (
    <div >
      <Navbar />
      <Home />
      <About />
      <Skills />
      <Works />
      <Contact />
    </div>
  );
}

export default App;

Here’s what your code is doing:

  • Importing each of the components with the import statement from their respective locations in the project directory.

  • Including each component in the App function within the return statement, specifying the order in which they should be rendered.

Styling the components

Now that you have created and rendered your components, you need to add some CSS styling to display a nice UI for your components. In your index.css, modify the styling using Tailwind as follows:

@tailwind base;
@tailwind components;
@tailwind utilities;
@import url('https://fonts.googleapis.com/css2?family=Raleway:wght@300;400;500;600;700;800;900&display=swap');
@layer base { 
    body {
        @apply font-[Raleway];
    }
    li {
        @apply px-4;
        @apply cursor-pointer
    }
}
.content-div {
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center;
    height: 250px;
}
.content-div:hover {
    background-image: linear-gradient(
        to right,
        rgba(112, 157, 255, 0.8),
        hsla(242, 74%, 61%, 0.8)   
    )!important;
}

How to build the navigation bar

Let’s start with the first section, the Navbar component. Your React portfolio needs a navigation bar because it's a single-page application (SPA) that dynamically renders content within a single page. Visitors to your website will use the navigation bar to jump between different sections, such as About, Skills, Work, etc., without reloading the entire page.

Your portfolio has two parts: the desktop view and the mobile view. Therefore, you need to create navigation menus for both desktop and mobile. 

Your desktop menu will contain a logo and links to your Home, About, Skills, Work, and Contact sections. It will also include social icons that link to your LinkedIn, GitHub, email, and resume. The mobile menu will feature a hamburger icon to toggle visibility, with each section stacked vertically.

In your Navbar.jsx file, update your code with the following:

import React, { useState } from 'react'; 
import {
  FaBars,
  FaTimes,
  FaGithub,
  FaLinkedin,
  FaFacebook,
  FaLinkedinIn,
} from 'react-icons/fa';
import { HiOutlineMail } from 'react-icons/hi';
import { BsFillPersonLinesFill } from 'react-icons/bs';
import { Link } from 'react-scroll';

const Navbar = () => {
  const [nav, setNav] = useState(false);
  const handleClick = () => setNav(!nav);

  return (
    <div className='fixed w-full h-[80px] flex justify-between items-center px-4 bg-[#0a192f] text-gray-300'>
      <div>
        <h1 className=' font-thin text-2xl italic font-serif'>TB</h1>
      </div>
      {/* menu */}
      <ul className='hidden md:flex gap-x-8'>
        <li>
          <Link to='home' smooth={true} duration={500}>
            Home
          </Link>
        </li>
        <li>
          <Link to='about' smooth={true} duration={500}>
            About
          </Link>
        </li>
        <li>
          <Link to='skills' smooth={true} duration={500}>
            Skills
          </Link>
        </li>
        <li>
          <Link to='work' smooth={true} duration={500}>
            Work
          </Link>
        </li>
        <li>
          <Link to='contact' smooth={true} duration={500}>
            Contact
          </Link>
        </li>
      </ul>
      {/* Hamburger */}
      <div onClick={handleClick} className='md:hidden z-10'>
        {!nav ? <FaBars /> : <FaTimes />}
      </div>
      {/* Mobile menu */}
      <ul
        className={
          !nav
            ? 'hidden'
            : 'absolute top-0 left-0 w-full h-screen bg-[#0a192f] flex flex-col justify-center items-center'
        }
      >
        <li className='py-6 text-4xl'>
          <Link onClick={handleClick} to='home' smooth={true} duration={500}>
            Home
          </Link>
        </li>
        <li className='py-6 text-4xl'>
          {' '}
          <Link onClick={handleClick} to='about' smooth={true} duration={500}>
            About
          </Link>
        </li>
        <li className='py-6 text-4xl'>
          {' '}
          <Link onClick={handleClick} to='skills' smooth={true} duration={500}>
            Skills
          </Link>
        </li>
        <li className='py-6 text-4xl'>
          {' '}
          <Link onClick={handleClick} to='work' smooth={true} duration={500}>
            Work
          </Link>
        </li>
        <li className='py-6 text-4xl'>
          {' '}
          <Link onClick={handleClick} to='contact' smooth={true} duration={500}>
            Contact
          </Link>
        </li>
      </ul>
      {/* Social icons */}
      <div className='hidden lg:flex fixed flex-col top-[35%] left-0'>
        <ul>
          <li className='w-[160px] h-[60px] flex justify-between items-center ml-[-100px] hover:ml-[-10px] duration-300 bg-blue-600'>
            <a
              className='flex justify-between items-center w-full text-gray-300'
              href='/'
            >
              Linkedin <FaLinkedin size={30} />
            </a>
          </li>
          <li className='w-[160px] h-[60px] flex justify-between items-center ml-[-100px] hover:ml-[-10px] duration-300 bg-[#333333]'>
            <a
              className='flex justify-between items-center w-full text-gray-300'
              href='/'
            >
              Github <FaGithub size={30} />
            </a>
          </li>
          <li className='w-[160px] h-[60px] flex justify-between items-center ml-[-100px] hover:ml-[-10px] duration-300 bg-[#6fc2b0]'>
            <a
              className='flex justify-between items-center w-full text-gray-300'
              href='/'
            >
              Email <HiOutlineMail size={30} />
            </a>
          </li>
          <li className='w-[160px] h-[60px] flex justify-between items-center ml-[-100px] hover:ml-[-10px] duration-300 bg-[#565f69]'>
            <a
              className='flex justify-between items-center w-full text-gray-300'
              href='/'
            >
              Resume <BsFillPersonLinesFill size={30} />
            </a>
          </li>
        </ul>
      </div>
    </div>
  );
};
export default Navbar;

In the code block above, you did the following:

  • Imported the following:

    • The useState hook from React, which allows the component to manage its state when the mobile menu is opened or closed.

    • Various icons from the react-icons/fa library to enable the use of icons such as the hamburger menu, close button, social media logos, etc.

    • The HiOutlineMail from the react-icons/hi library for a separate icon set dedicated to email.

    • A resume icon named BsFillPersonLinesFill from the react-icons/bs library, offering additional icon options.

    • The Link component from react-scroll to facilitate smooth scrolling to sections within the page when clicking on navigation links.

  • Defined the state and behavior of the mobile menu with const [nav, setNav] = useState(false):

    • useState(false) initializes a state variable called nav with an initial value of false, indicating that the mobile menu is hidden by default.

    • [nav, setNav] destructures the return value of useState into a nav variable, which stores the current state, and a setNav function that allows you to update the state.

  • Created a handleClick function with const handleClick = () => setNav(!nav). This function is triggered when the hamburger menu is clicked, toggling the nav state (showing the menu if hidden and vice versa).

How to build a Home component for your landing page

You need to build a Home component for your landing page on your portfolio to serve as the first content your visitors see when they visit your portfolio website. It should give a brief introduction and highlight your skills and experience.

The Home component will contain a bold headline, like 'I'm a Full Stack Web Developer,' that declares your profession, a paragraph highlighting your experience and passion for specific technologies, and a call to action that prompts visitors to click on an About Me button, inviting them to learn more about your work. It should also contain your profile picture along with a brief description.

In your Home.jsx file, implement this by updating your code with the following:

import React from 'react';
import { HiArrowNarrowRight } from 'react-icons/hi';
import me from '../assets/me.png';
import { Link } from "react-scroll"; 

const Home = () => {
  return (
    <div
    name="home"
    className="h-screen w-full bg-[#0a192f]"
  >
    <div className="max-w-screen-lg mx-auto flex flex-col items-center justify-center h-full px-4 md:flex-row">
      <div className="flex flex-col justify-center h-full">
        <h2 className="text-4xl sm:text-7xl font-bold text-white">
          I'm a Full Stack Web Developer
        </h2>
        <p className="text-gray-500 py-4 max-w-md">
           I have 4 years of experience in graphics design and web development.
          Currently, I love to work on web application using technologies like
          React, Tailwind, Next.js and Mongodb.
        </p>
        <div>
          <Link
            to="about"
            smooth
            duration={500}
            className="group text-white w-fit px-6 py-3 my-2 flex items-center rounded-md bg-gradient-to-r from-cyan-500 to-blue-500 cursor-pointer"
          >
            About Me
            <span className="group-hover:rotate-90 duration-300">
              <HiArrowNarrowRight size={25} className="ml-3" />
            </span>
          </Link>
        </div>
      </div>
      <div>
        <img
          src={me}  
          alt="my profile"
          className="rounded-2xl mx-auto w-2/3 md:w-full"
        />
      </div>
    </div>
  </div>
  );
};
export default Home;

In the code block above, you did the following:

  • Imported the right arrow icon HiArrowNarrowRight from the react-icons/hi library for the About Me button.

  • Imported “me,” your profile picture, from the assets folder.

  • Imported Link to enable smooth scrolling to different sections within the page.

  • Added styles to the main div container to determine the appearance of the landing page for full screens, small screens, and medium screens.

  • Rendered the bold heading, paragraph, and About Me button, which links to the About section, with additional CSS styles.

  • Rendered your profile image with CSS styles, giving it rounded corners for a polished look.

Run your application with the following command to see how the landing page looks in your browser:

npm start

Go to your localhost URL in your browser, and you should see the following:

Rendered landing section

How to add an About section with React

Let’s proceed to build the About section of your Portfolio. You should introduce yourself, your professional identity, and your expertise to your visitors.

Add a bold “About” title, greeting, and a short Bio in your About component. To implement this, open your About.jsx file and update your code with the following: 

import React from "react";

const About = () => { 
  return (
    <div
      name="about"
      id="about"
      className="w-full h-screen bg-[#0a192f] text-gray-300"
    >
      <div className="flex flex-col justify-center items-center w-full h-full">
        <div className=" py-16 rounded-md bg-cyan-800 flex flex-col justify-center items-center w-4/6">
          <div className="max-w-[1000px] w-full grid grid-cols-2 gap-8 mb-4">
            <div className="sm:text-right pb-8 pl-4">
              <p className="text-4xl font-bold inline border-b-4 border-cyan-500">
                About
              </p>
            </div>
            <div></div>
          </div>
          <div className="max-w-[1000px] w-full grid sm:grid-cols-2 gap-8 px-4">
            <div className="sm:text-right text-4xl font-bold">
              <p>
                Hi. I'm Taminoturoko Briggs, nice to meet you. Please take a
                look around.
              </p>
            </div>
            <div>
              <p>
                {" "}
                A software developer with experience in building Responsive and
                Scalable Web apps. I am well-knowledged in UI/UX principles and
                practices. In addition to software development, I am also a
                technical writer--simplifying topics/concepts on the web.
              </p>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};
export default About;

In the code block above, you did the following:

  • Styled a div container using the grid layout properties grid and grid-cols and conditional rendering properties like sm:text-right for the Bio. You divided the div container into two columns: one for your greeting and the other for your Bio.

  • Added some CSS styles to align the title and greeting text to the right on small screens and render it large and bold.

  • Added an empty div to balance the layout on small screens and take up the second column.

  • Rendered your Bio with regular paragraph formatting.

Your code automatically refreshes. To view the changes made to the About section, navigate to your browser and click the About Me button on the landing page. This is how your About section looks:

Rendered about section

How to add a Skills section for your React portfolio

Let’s build the Skills section for your portfolio to showcase your technical expertise. You’ll create a list of the different technologies you have worked with in this section.

Add a title and introduction text and include a list of technologies underneath. To implement this, open your Skills.jsx file and add the following code:

import React from 'react';

const Skills = () => {
  return (
    <div name='skills' className='w-full h-screen bg-[#0a192f] text-gray-300'>
      {/* Container */}
      <div className='max-w-[1000px] mx-auto p-4 flex flex-col justify-center w-full h-full'>
          <div className=' w-full flex justify-center items-center flex-col mb-7'>
              <p className='text-4xl font-bold inline border-b-4 border-cyan-500 text-center '>Skills</p>
              <p className='py-4 text-2xl'>I enjoy diving into and learning new things. Here's a list of technologies I've worked with</p>
          </div> 
          <div className='w-full grid grid-cols-2 sm:grid-cols-4 gap-4 text-center py-8'>
              <div className='shadow-md shadow-[#040c16] hover:scale-110 duration-500'>
                  <p className='my-4'>HTML</p>
              </div>
              <div className='shadow-md shadow-[#040c16] hover:scale-110 duration-500'>
                  <p className='my-4'>CSS</p>
              </div>
              <div className='shadow-md shadow-[#040c16] hover:scale-110 duration-500'>
                  <p className='my-4'>JAVASCRIPT</p>
              </div>
              <div className='shadow-md shadow-[#040c16] hover:scale-110 duration-500'>
                  <p className='my-4'>REACT</p>
              </div>
              <div className='shadow-md shadow-[#040c16] hover:scale-110 duration-500'>
                  <p className='my-4'>GITHUB</p>
              </div>
              <div className='shadow-md shadow-[#040c16] hover:scale-110 duration-500'>
                  <p className='my-4'>NODE JS</p>
              </div>
              <div className='shadow-md shadow-[#040c16] hover:scale-110 duration-500'>
                  <p className='my-4'>MONGO DB</p>
              </div>
              <div className='shadow-md shadow-[#040c16] hover:scale-110 duration-500'>
                  <p className='my-4'>AWS</p>
              </div>
              <div className='shadow-md shadow-[#040c16] hover:scale-110 duration-500'>
                  <p className='my-4'>Django</p>
              </div>
              <div className='shadow-md shadow-[#040c16] hover:scale-110 duration-500'>
                  <p className='my-4'>Sass</p>
              </div>
              <div className='shadow-md shadow-[#040c16] hover:scale-110 duration-500'>
                  <p className='my-4'>Mongodb</p>
              </div>
              <div className='shadow-md shadow-[#040c16] hover:scale-110 duration-500'>
                  <p className='my-4'>GraphQl</p>
              </div>
          </div>
      </div>
    </div>
  );
};
export default Skills;

In your code, you did the following:

  • Set the “Skills” title to be large and bold with additional CSS styling, using className for the positioning.

  • Rendered the introduction paragraph.

  • Created a grid layout to list the technologies, with two columns on small screens and four on larger screens.

Go to your portfolio in your browser, navigate to the Skills section, and you will see the following:

Rendered skills section

How to build a Works section with React

Let’s proceed to build the Works section of your React Portfolio, which will showcase your work and demonstrate your skills and abilities.

The Works component will render a grid-like presentation of your various projects. When a user hovers over any projects, an overlay with additional information and buttons will be displayed.

To implement this, open your Work.jsx file and update your code with the following:

import React from 'react';
import code from '../assets/code2.png';

const Works = () => {
  return (
    <div name='work' className='w-full md:h-screen text-gray-300 bg-[#0a192f]'>
      <div className='max-w-[1000px] mx-auto p-4 flex flex-col justify-center w-full h-full'>
        <div className='pb-8 w-full flex justify-center items-center flex-col'>
          <p className='text-4xl font-bold inline border-b-4 text-gray-300 border-cyan-500'>
            Work
          </p>
          <p className='py-6 text-2xl'>Check out some of my most recent work</p>
        </div>
{/* Container */}
        <div className='grid sm:grid-cols-2 md:grid-cols-3 gap-4'>
            {/* Grid Item */}
          <div
            style={{ backgroundImage: `url(${code})` }}
            className='shadow-lg shadow-[#040c16] group container rounded-md flex justify-center items-center mx-auto content-div'
          >
            {/* Hover Effects */}
            <div className='opacity-0 group-hover:opacity-100 flex justify-center items-center flex-col'>
              <span className=' text-lg font-bold text-white tracking-wider'>
                CBT Application
              </span>
              <p className='text-center'>A CBT web application built with React and Mongodb</p>
              <div className='pt-8 text-center'>
                <a href='/'>
                  <button className='text-center rounded-lg px-4 py-3 m-2 bg-white text-gray-700 font-bold text-lg'>
                    Demo
                  </button>
                </a>
                <a href='/'>
                  <button className='text-center rounded-lg px-4 py-3 m-2 bg-white text-gray-700 font-bold text-lg'>
                    Code
                  </button>
                </a>
              </div>
            </div>
          </div>
          <div
            style={{ backgroundImage: `url(${code})` }}
            className='shadow-lg shadow-[#040c16] group container rounded-md flex justify-center items-center mx-auto content-div'
          >
            {/* Hover Effects */}
            <div className='opacity-0 group-hover:opacity-100 flex justify-center items-center flex-col'>
              <span className=' text-lg font-bold text-white tracking-wider'>
                CBT Application
              </span>
              <p className='text-center'>A CBT web application built with React and Mongodb</p>
              <div className='pt-8 text-center'>
                <a href='/'>
                  <button className='text-center rounded-lg px-4 py-3 m-2 bg-white text-gray-700 font-bold text-lg'>
                    Demo
                  </button>
                </a>
                <a href='/'>
                  <button className='text-center rounded-lg px-4 py-3 m-2 bg-white text-gray-700 font-bold text-lg'>
                    Code
                  </button>
                </a>
              </div>
            </div>
          </div>
          <div
            style={{ backgroundImage: `url(${code})` }}
            className='shadow-lg shadow-[#040c16] group container rounded-md flex justify-center items-center mx-auto content-div'
          >
            {/* Hover Effects */}
            <div className='opacity-0 group-hover:opacity-100 flex justify-center items-center flex-col'>
              <span className=' text-lg font-bold text-white tracking-wider'>
                CBT Application
              </span>
              <p className='text-center'>A CBT web application built with React and Mongodb</p>
              <div className='pt-8 text-center'>
                <a href='/'>
                  <button className='text-center rounded-lg px-4 py-3 m-2 bg-white text-gray-700 font-bold text-lg'>
                    Demo
                  </button>
                </a>
                <a href='/'>
                  <button className='text-center rounded-lg px-4 py-3 m-2 bg-white text-gray-700 font-bold text-lg'>
                    Code
                  </button>
                </a>
              </div>
            </div>
          </div>
          <div
            style={{ backgroundImage: `url(${code})` }}
            className='shadow-lg shadow-[#040c16] group container rounded-md flex justify-center items-center mx-auto content-div'
          >
            {/* Hover Effects */}
            <div className='opacity-0 group-hover:opacity-100 flex justify-center items-center flex-col'>
              <span className=' text-lg font-bold text-white tracking-wider'>
                CBT Application
              </span>
              <p className='text-center'>A CBT web application built with React and Mongodb</p>
              <div className='pt-8 text-center'>
                <a href='/'>
                  <button className='text-center rounded-lg px-4 py-3 m-2 bg-white text-gray-700 font-bold text-lg'>
                    Demo
                  </button>
                </a>
                <a href='/'>
                  <button className='text-center rounded-lg px-4 py-3 m-2 bg-white text-gray-700 font-bold text-lg'>
                    Code
                  </button>
                </a>
              </div>
            </div>
          </div>
          <div
            style={{ backgroundImage: `url(${code})` }}
            className='shadow-lg shadow-[#040c16] group container rounded-md flex justify-center items-center mx-auto content-div'
          >
            {/* Hover Effects */}
            <div className='opacity-0 group-hover:opacity-100 flex justify-center items-center flex-col'>
              <span className=' text-lg font-bold text-white tracking-wider'>
                CBT Application
              </span>
              <p className='text-center'>A CBT web application built with React and Mongodb</p>
              <div className='pt-8 text-center'>
                <a href='/'>
                  <button className='text-center rounded-lg px-4 py-3 m-2 bg-white text-gray-700 font-bold text-lg'>
                    Demo
                  </button>
                </a>
                <a href='/'>
                  <button className='text-center rounded-lg px-4 py-3 m-2 bg-white text-gray-700 font-bold text-lg'>
                    Code
                  </button>
                </a>
              </div>
            </div>
          </div>
          <div
            style={{ backgroundImage: `url(${code})` }}
            className='shadow-lg shadow-[#040c16] group container rounded-md flex justify-center items-center mx-auto content-div'
          >
            {/* Hover Effects */}
            <div className='opacity-0 group-hover:opacity-100 flex justify-center items-center flex-col'>
              <span className=' text-lg font-bold text-white tracking-wider'>
                CBT Application
              </span>
              <p className='text-center'>A CBT web application built with React and Mongodb</p>
              <div className='pt-8 text-center'>
                <a href='/'>
                  <button className='text-center rounded-lg px-4 py-3 m-2 bg-white text-gray-700 font-bold text-lg'>
                    Demo
                  </button>
                </a>
                <a href='/'>
                  <button className='text-center rounded-lg px-4 py-3 m-2 bg-white text-gray-700 font-bold text-lg'>
                    Code
                  </button>
                </a>
              </div>
            </div>
          </div>
          
        </div>
      </div>
    </div>
  );
};
export default Works;

In your code, you did the following:

  • Created a grid layout to display projects, adjusting the number of columns based on the screen size using grid sm:grid-cols-2 md:grid-cols-3 gap-4.

  • Added a hidden layer that reveals information on hover.

  • Included two buttons, Demo and Code, on each card. These buttons link to external URLs containing your projects.

Go to your portfolio in your browser, click on the Works section, and you will see the following:

undefined

How to build a Contact section with React

Let’s build the last section, the Contact component, which will contain a form that visitors can use to reach out to you.

The Contact section will include a “Contact” title, a short text, a form that accepts Name, Email, and Message, and a Let’s Collaborate button.

To implement this, open your Contact.jsx file and update your code with the following:

import React from 'react'

const Contact = () => {
  return (
    <div name='contact' className='w-full h-screen bg-[#0a192f] flex justify-center items-center p-4'>
        <div className='flex flex-col max-w-[600px] w-full'>
            <div className='pb-8 flex flex-col justify-center w-full h-full items-center'>
                <p className='text-4xl font-bold inline border-b-4 border-cyan-500 text-gray-300'>Contact</p>
                <p className='text-gray-300 py-4'>Send me a message</p>
            </div>
            <input className='bg-[#ccd6f6] p-2' type="text" placeholder='Name' name='name' />
            <input className='my-4 p-2 bg-[#ccd6f6]' type="email" placeholder='Email' name='email' />
            <textarea className='bg-[#ccd6f6] p-2' name="message" rows="10" placeholder='Message'></textarea>
            <button className='text-white border-2 hover:bg-cyan-500 hover:border-cyan-500 px-4 py-3 my-8 mx-auto flex items-center'>Let's Collaborate</button>
        </div>
    </div>
  )
}
export default Contact

Go to your portfolio in your browser and click on the Contact section. It should look as follows:

React portfolio contact section

Setting up our React portfolio content in ButterCMS

Now that you have built all the components and sections of your portfolio, you’ll need to add some content. You can do that using ButterCMS, a headless CMS that is seamless to use.

To get started, go to the ButterCMS website and click the Get Started button or Log In (if you already have an account). 

Create an account by signing up with either your Google or GitHub account. 

After signing up, you’ll be directed to your user dashboard where you can set up a page that will contain all the data (or content) you want displayed on your portfolio site.

Creating a new portfolio page

The sections of your website will be divided into individual components that make up the page. Let’s go over how to set this up. From the left sidebar of your ButterCMS dashboard, click the Page Types plus icon:

Create a new page type for the portfolio page.

The following page will open. On this new page, you will set up the content structure for each individual section of your website. From the side menu, select Component Picker:

Creating a component picker in ButterCMS for the portfolio page.

Creating the portfolio’s Home component

Next, enter a name for the page and create the first section. Name the Component Picker “My Personal Portfolio” and click the Create Component button. Then, create the first component, name it “Landing Section,” and do the following:

  • Add a description: “This will be the section for our landing page.”

  • Add two text fields, one for the caption and one for the main text of your landing page by doing the following:

    • Select the Long Text field and enter “landing caption.”

    • Select the Long Text field and enter “landing main text.”

Check the GIF below to see how it is structured:Creating the landing page component in ButterCMS.

Creating the portfolios About component

To create the next section, click the Create Component button at the bottom of the page to add another component. Name the component “About section.” Then, add two fields to the component for the caption and main text by doing the following:

  • Select the Short Text field and enter “About caption.”

  • Select the Long Text field and enter “About main details.”

Your component should look as follows:

Configuring the "About" component in ButterCMS.

Creating the portfolio's skills and works section Components

The Skills section will include a text field and a list of various technologies. To accomplish this, you'll need an array-like structure, which can be achieved using a Repeater. A Repeater is a group of content fields that can be replicated on a web page.

To create the Skills component, select Create Component and add a description if you wish. Then, do the following:

  • Select the Long Text field and enter “skills header.”

  • Select the Repeater field and name it “skills.”:

    • Choose the Short Text field to enter each of the names of your skills.

Refer to the following GIF to see the added fields:

Configuring the Skills component in ButterCMS.

With the Repeater, you can add more than one skill when entering content for your page.

Next, for your Works section, click the Create Component button at the bottom of the page to add another component.

Create the Works section similar to how you created the Skills section by adding the following fields:

  • Select the Long Text field and enter “work header.”

  • Select the Repeater field and name it “works”:

    • Select the Short Text field and enter “work title.”

    • Select the Long Text field and enter “work description.”

    • Select the Media field and enter “work image.”

    • Select the Short Text field and enter “github url”' for the GitHub link to your project.

    • Select the Short Text field and enter “demo” for the demo link to your project.

Check the following GIF to see how the fields were added:

Configuring the "Works" component in ButterCMS.

From the GIF above, you can see that each project defined using the Repeater will have a title, a description, an image, and two URLs for the project’s code and demo.

To save the page, click the Create Page Type button at the top and enter “portfolio” in the page-type-name field.

How to create the portfolio website content

With the page setup complete, you will add the content for your site to the page. Later, you'll fetch and display this content from the CMS in your application. To do this, select the created page, “portfolio,” from the page options on the left sidebar as follows:

Select Portfolio page type

Afterward, you'll be prompted to enter a Page Title, which will serve as the title of the created page. Enter “a portfolio site” into the field as follows:

Name portfolio page

To add new content, click on the plus icon to access the component picker, as shown below:

Select component picker

Then, select the content structure you want to use from the list of components you defined for your page, as follows:

undefined

After the selection, you can add the required content to the fields by populating each section. Begin with the Landing section and add the following content to the fields:

  • Landing caption: “I'm a Full Stack Web Developer.”

  • Landing main text: “I have four years of experience in graphic design and web development. Currently, I love working on web applications using technologies like React, Tailwind, Next.js, and MongoDB.”

Your Landing section should look like this:

Adding content to the landing page section in ButterCMS.

For your About section, add the following content to the fields:

  • About caption: “Hi, I'm Taminoturoko Briggs. Nice to meet you. Please take a look around.”

  • About main details: “I am a software developer with experience in building responsive and scalable web applications. I possess a strong understanding of UI/UX principles and practices. In addition to software development, I am also a technical writer, simplifying topics and concepts on the web.”

Your About section should look like this:

About section content

For your Skills section, add the following content:

  • Skill header: “I enjoy diving into and learning new things. Here's a list of technologies I've worked with:”

  • Skills: “HTML, JavaScript, and CSS”

Your Skills section should look like this:

Add content to the skills section in ButterCMS.

For your Works section, add the following content:

  • Works header: “Check out some of my most recent work.”

  • Works:

    • Work title: “Web design”

    • Work description: “This is a web design for a portfolio site.”

    • Insert an image of choice in the work image section.

Your Works section should look like this:

Adding content to the works section in ButterCMS.

To save and publish the changes that you have made, click on the Save Draft and Publish buttons at the top of the page.

Lastly, connecting our React portfolio site to ButterCMS

To connect your application to ButterCMS, you will need the Read API Token, which can be found in the settings tab of your account. To locate it, go to Settings as follows:

Select settings

Copy your Read API Token:

Copy api token

Next, set up a fetch request to return data from the content you added in ButterCMS. To do this, update the code in your App.js file with the following code and replace “your read token” with the Read API Token you copied:

//...
import {React, useEffect, useState} from "react";
import axios from "axios";

function App() { 
  const readtoken = "your read token"
  const [data, setData] = useState([]);

  useEffect(() => {
    const getData = async () => {
      axios.get(`https://api.buttercms.com/v2/pages/portfolio/a-portfolio-site?auth_token=${readtoken}`).then(res => {
        setData(res.data.data.fields.my_personal_porfolio);
      }).catch(err => {
        console.log(err);
      })
    }
    getData();
  }, []);
  return (
    <div>
      <Navbar />
      <Home content={data[0]}/>
      <About content={data[1]}/>
      <Skills content={data[2]}/>
      <Works content={data[3]}/>
      <Contact />
    </div>
  );
}
//...

In the code block above, you set up a fetch request that returns data from the CMS. When the request is executed, the value of the state data is set to the returned value. Additionally, you passed the corresponding data elements as props to each component.

To set up your Home component to use the CMS content you added, you’ll need to update the code in your Home.jsx file as follows:

  • Pass in {content} as a prop to your Home component.

  • Replace the h2 text with {content?.fields.landing_caption}.

  • Replace the p text with {content?.fields.landing_main_text}.

Update your Home.jsx file with the following code:

const Home = ({content}) => {
//....
 <h2 className="text-4xl sm:text-7xl font-bold text-white">
    {content?.fields.landing_caption}
  </h2>
  <p className="text-gray-500 py-4 max-w-md">
    {content?.fields.landing_main_text}
  </p>

To set up your About component to use the CMS content, you’ll need to do the following:

  • Pass in {content} as a prop to your About component.

  • Replace your Greeting text with {content?.fields.about_caption}.

  • Replace your Bio text with {content?.fields.about_main_details}.

Update your About.jsx file with the following code:

const About = ({content}) => {
//...
<div className="max-w-[1000px] w-full grid sm:grid-cols-2 gap-8 px-4">
<div className="sm:text-right text-4xl font-bold">
  <p>
   {content?.fields.about_caption}
  </p>
</div>
<div>
  <p>
    {" "}
    {content?.fields.about_main_details}
  </p>
</div>
</div>

To set up your Skills component to use the CMS content, you’ll need to do the following:

  • Pass {content} as a prop to your Skills component.

  • Replace your skills introduction text with {content?.fields.skill_header}.

  • Use {content?.fields.skills.map((skill, index) => {})} to map through the skills.

  • Replace the skills with {skill.terminology_learnt}.

Update your Skills.jsx file with the following code:

const Skills = ({content}) => {
//....
<p className="text-4xl font-bold inline border-b-4 border-cyan-500 text-center ">
      Skills
    </p>
    <p className="py-4 text-2xl">{content?.fields.skill_header}</p>
  </div>
  <div className="w-full grid grid-cols-2 sm:grid-cols-4 gap-4 text-center py-8">
    {content?.fields.skills.map((skill, index) => {
      return (
        <div className="shadow-md shadow-[#040c16] hover:scale-110 duration-500" key={index}>
          <p className="my-4">{skill.terminology_learnt}</p>
        </div>
      );
    })}
  </div>

Finally, to set up your Works component to use the CMS content, do the following:

  • Replace the introduction text with {content?.fields.work_header}.

  • Add {content?.fields.works.map((work, index) => {})} to map through the projects.

  • Replace the background image with work.work_image.

  • Replace your work title with {work.work_title}.

  • Replace your work description with {work.work_description}.

  • For your Demo button, add {work.github_url} to your `href` property.

  • For your Code button, add {work.demo_url}.

Update your Works.jsx file with the following code:

const Works = ({content}) => {
//....
<p className="text-4xl font-bold inline border-b-4 text-gray-300 border-cyan-500">
    Works
  </p>
  <p className="py-6 text-2xl">{content?.fields.work_header}</p>
</div>
{/* Container */}
<div className="grid sm:grid-cols-2 md:grid-cols-3 gap-4">
  {/* Grid Item */}
  {content?.fields.works.map((work, index) => {
    return (
      <div
        style={{ backgroundImage: `url(${work.work_image})` }}
        className="shadow-lg shadow-[#040c16] group container rounded-md flex justify-center items-center mx-auto content-div"
        key={index}
      >
        {/* Hover Effects */}
        <div className="opacity-0 group-hover:opacity-100 flex justify-center items-center flex-col">
          <span className=" text-lg font-bold text-white tracking-wider">
            {work.work_title}
          </span>
          <p className="text-center">
            {work.work_description}
          </p>
          <div className="pt-8 text-center">
            <a href={work.github_url}>
              <button className="text-center rounded-lg px-4 py-3 m-2 bg-white text-gray-700 font-bold text-lg">
                Demo
              </button>
            </a>
            <a href={work.demo_url}>
              <button className="text-center rounded-lg px-4 py-3 m-2 bg-white text-gray-700 font-bold text-lg">
                Code
              </button>
            </a>
          </div>
        </div>
      </div>
    );
  })}
</div>

Now, if you view your application in the browser, you’ll see a result similar to the GIF below:

Tutorial results: A rendered portfolio website.

From the GIF, you can see that the content displayed on your portfolio page matches the content of your CMS.

Examples of portfolio websites built with React

React offers many benefits and functionalities, making it a go-to choice for building portfolio websites. As a result, many developers choose to build their portfolio websites with React, and you can find these portfolios online. You can explore them and draw insights to build a unique portfolio that stands out. 

Let's discuss some examples of good portfolio websites:

Hafiz Kadir portfolio

This is a good example of a portfolio website that leverages React to add animations and transitions, making the website more engaging and visually appealing. To see how it looks, clone the Github repository, run the code in your terminal, and open it in your browser:

React portfolio example #1

Alpay’s portfolio

This portfolio has a highly interactive UI and a well-designed, component-based architecture. It was also developed using other third-party libraries supported by React. The source code of the portfolio can be found in the Github repository. This is how the website looks:

React portfolio example #2

Developer and Designer portfolio

This is a simple portfolio website built using React.js. It features a clean and minimalist UI design with well-implemented light and dark modes (powered by a theme provider built with React). The website has smooth transitions and is mobile-responsive. Clone the Github repository and run the code to see how it looks:

React portfolio example #3

Ed Park portfolio

This is a well-designed portfolio website created using React. It has robust routing through React Router, supports both dark and light modes, and is fully responsive for mobile devices. You can check more information about the portfolio:

React portfolio example #4

Note that while the portfolio in this tutorial isn't responsive, responsiveness is equally important, just like making your portfolio concise.

Also, to make your portfolio stand out to recruiters and clients, you can add some creative and interactive animations to it. The following libraries can help you easily do this: Framer Motion, tsParticles, and Three.js.

React portfolio website templates to use

If you prefer not to go through the stress of building your portfolio from scratch; you can leverage portfolio templates built with React that are customizable to suit your needs. Let's explore some of these templates:

DevFolio

This is a one-page layout portfolio template built with React, fully responsive with a modern UI design, animations, and hover effects. It is an excellent choice and easy to use due to its well-organized documentation. Clone the repository to get started.

Full-stack developer portfolio

This is a software developer portfolio template built with React, Next.js, and other technologies. It has a good component structure for sections that you can customize to showcase your skills and experiences. To use this template, clone the repository.

Software developer portfolio

This is a Multi-Page Layout portfolio template built with React, Node.js, and other technologies. It is fully responsive and styled with React-Bootstrap and CSS, offering easy-to-customize colors. Clone the repository and read the documentation on how to use it.

Closing thoughts

And there you have it! In this tutorial, you learned how to build a portfolio website with React, set up a content structure for it on ButterCMS, and retrieve the content for your application.

You also explored several good examples of portfolio websites and customizable responsive templates built with React. Using ButterCMS to seamlessly manage your website’s content is an excellent choice. It makes it easier to update, view, and manage the content of your application.

To learn more about using ButterCMS for your websites, check out the documentation.

Make sure you receive the freshest tutorials and Butter product updates.
Taminoturoko Briggs

Taminoturoko Briggs is a software developer and technical writer with sound knowledge of different web technologies. His core languages include JavaScript and Python.

ButterCMS is the #1 rated Headless CMS

G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award

Don’t miss a single post

Get our latest articles, stay updated!