GSD

How to Build a Portfolio Website with React

Posted by Taminoturoko Briggs on December 17, 2024

Every line of code you write in your portfolio demonstrates what you can build and how you think, solve problems, and stay current with modern web development practices. 

While a GitHub profile rich with contributions can be equally compelling, having both means you're maximizing your visibility to potential employers –and that's exactly what we'll help you achieve.

In this step-by-step tutorial, you'll learn how to build a professional portfolio website using React and Tailwind CSS, with ButterCMS handling your content management. 

By the end, you'll have learned how to build a portfolio website with React that showcases your projects and skills while being easy to maintain and update.

The portfolio we'll be building

In this tutorial, we'll build a modern React portfolio website with essential sections that every developer needs: 

  • A home and about section to make a solid first impression  

  • A skills showcase highlighting your technical expertise 

  • A projects section featuring your best work and GitHub contributions 

  • Smooth navigation between sections for a better user experience 

  • A contact section to connect with potential employers 

Note: Each section is built as a reusable React component, making your portfolio easy to maintain and update. You can find the complete code in this GitHub repo and follow along step by step. 

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

Portfolio landing page

Tools you'll need to create your React portfolio

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.

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

  • ButterCMS: Rather than hardcoding your portfolio content, we'll use this headless CMS to make your portfolio content dynamic and easy to update. With Butter, you can update your projects without touching code, manage your skills and experience through a user-friendly dashboard, and deploy content changes instantly. Start your free 14-day trial to follow along! 
  • Tailwind CSS: Modern portfolios need to look professional across all devices. Tailwind's utility-first approach helps us build responsive layouts quickly, maintain consistent styling, create smooth hover effects and transitions, and customize the design to match your personal brand.
  • React-scroll: First impressions matter. The react-scroll library helps create smooth scrolling between sections, giving your portfolio a polished, professional feel when visitors navigate through your work
  • React Icons: A portfolio needs visual elements to engage visitors. React Icons gives us access to social media icons for your profiles, tech stack icons for your skills section, and UI icons for navigation and interaction.
  • 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. To keep your portfolio dynamic, we'll use Axios to fetch your latest content from ButterCMS, keep your portfolio data up to date, and handle API requests efficiently.

Getting started: Setting up your 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.

Create a basic React component structure for each section

When building a React portfolio project, starting with a clean component-based architecture structure sets you up for success. Think of components as building blocks –each section of your portfolio (Home, About, Skills, etc.) will be its own independent piece that you can develop, style, and update without affecting the others.

First, create a components folder in your src directory with these files:

.
└── 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

Let's create a basic component structure. Here's how to set up your About component (the others will follow the same pattern):

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

Create similar basic components for Navbar, Home, Skills, Works, and Contact. Each one should import React, define a functional component, and export it. 

Like this:

import React from 'react'

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

Just change the name of the function and the export for the component you’re creating. Also, feel free to change the text within the <div>.

Now that we have our modular foundation, let's assemble these components in App.js. The order of components matters for both visual hierarchy and SEO:

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;

For styling, we are using a combination of Tailwind CSS utilities and custom styles. The base styles in index.css establish the foundation of our portfolio:

This modular approach offers several benefits:

  1. Maintainability: Each component can be updated independently.

  2. Reusability: Components can be reused across different projects.

  3. Organization: It’s easier to find and fix issues when code is separated.

  4. Collaboration: Different team members can work on different components.

For styling, we're using Tailwind CSS because it offers:

  • Rapid prototyping with utility classes

  • Consistent design system

  • Built-in responsive design

  • No context switching between files

Alternative styling approaches you could consider:

  • CSS Modules for better CSS scoping

  • Styled Components for CSS-in-JS

  • SASS for more structured CSS

  • CSS Frameworks like Material UI or Chakra UI

You can find the complete styling in the index.css file of the GitHub repo. I personally prefer Tailwind for portfolios because it allows quick iterations and maintains consistency across components, but choose what matches your workflow best.

Now that we've covered styling options, let's walk through building one of the most important components of your portfolio - the navigation bar.

Every great portfolio using React needs smooth navigation that just works. Since we're building a single-page application, we'll create a responsive nav bar that lets visitors jump between sections easily and includes quick links to your professional profiles.

This navigation code creates three key elements:

  1. A desktop menu with a smooth-scrolling section links

  2. A mobile-friendly hamburger menu that expands into a full-screen navigation

  3. A social sidebar with icons for your professional profiles

The code uses React's useState hook for menu toggling and react-scroll for smooth navigation, while Tailwind handles the responsive design and animations. You can find the complete code here:

//Navbar.jsx

// Import necessary dependencies
import React, { useState } from 'react'; 
// Import icons we'll use for our navbar
import {
  FaBars,
  FaTimes,
  FaGithub,
  FaLinkedin,
} from 'react-icons/fa';
import { HiOutlineMail } from 'react-icons/hi';
import { BsFillPersonLinesFill } from 'react-icons/bs';
// Import Link for smooth scrolling between sections
import { Link } from 'react-scroll';

const Navbar = () => {
  // State to handle mobile menu toggle (open/closed)
  const [nav, setNav] = useState(false);
  const handleClick = () => setNav(!nav);

  return (
    // Main navbar container - fixed at top, full width
    <div className='fixed w-full h-20 flex justify-between items-center px-4 bg-slate-900 text-gray-300'>
      {/* Your logo or brand name */}
      <div>
        <h1 className='font-thin text-2xl italic font-serif'>TB</h1>
      </div>

      {/* Desktop Menu - hidden on mobile, flex on medium screens and up */}
      <ul className='hidden md:flex gap-x-8'>
        <li>
          <Link to='home' smooth={true} duration={500}>
            Home
          </Link>
        </li>
        {/* ... other menu items ... */}
      </ul>

      {/* Hamburger Icon - visible only on mobile */}
      <div onClick={handleClick} className='md:hidden z-10 cursor-pointer'>
        {!nav ? <FaBars size={20} /> : <FaTimes size={20} />}
      </div>

      {/* Mobile Menu - full screen overlay */}
      <ul className={!nav ? 'hidden' : 'absolute top-0 left-0 w-full h-screen bg-slate-900 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>
        {/* ... other mobile menu items ... */}
      </ul>

      {/* Social icons - hidden on smaller screens, shown on large screens */}
      <div className='hidden lg:flex fixed flex-col top-[35%] left-0'>
        <ul>
          {/* LinkedIn - sliding animation on hover */}
          <li className='w-40 h-14 flex justify-between items-center ml-[-100px] hover:ml-[-10px] duration-300 bg-blue-600'>
            <a href="https://linkedin.com" className='flex justify-between items-center w-full text-gray-300 px-4'>
              LinkedIn <FaLinkedin size={30} />
            </a>
          </li>
          {/* ... other social links ... */}
        </ul>
      </div>
    </div>
  );
};

export default Navbar;

How to build the Home component

First impressions matter - your Home component is the hero section that immediately tells visitors who you are and what you do.

The code below creates a responsive landing page with:

  • A compelling headline and introduction

  • Your professional photo

  • A stylish "About Me" button with hover animation

  • Smooth scrolling between sections

To personalize your home component, don’t forget to:

  1. Replace the placeholder text with your actual experience

  2. Update image import with your photo

  3. Adjust gradient colors to match your brand

Go to the Home.jsx file under src/components and implement this by updating your code with the following:

//Home.jsx
// Import required components and assets
import React from 'react';
import { HiArrowNarrowRight } from 'react-icons/hi'; // Arrow icon for button
import me from '../assets/me.png'; // Your profile photo
import { Link } from "react-scroll"; // For smooth scrolling

const Home = () => {
 return (
   // Main container - full screen with dark background
   <div name="home" className="h-screen w-full bg-[#0a192f]">
     {/* Content wrapper - centers content and handles responsive layout */}
     <div className="max-w-screen-lg mx-auto flex flex-col items-center justify-center h-full px-4 md:flex-row">
       {/* Left side - Text content */}
       <div className="flex flex-col justify-center h-full">
         {/* Main headline */}
         <h2 className="text-4xl sm:text-7xl font-bold text-white">
           I'm a Full Stack Web Developer
         </h2>
         {/* Brief introduction */}
         <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>
         {/* About Me button with hover effect */}
         <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>
       {/* Right side - Profile image */}
       <div>
         <img
           src={me}  
           alt="my profile"
           className="rounded-2xl mx-auto w-2/3 md:w-full"
         />
       </div>
     </div>
   </div>
 );
};

export default Home;

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 build the About component

The About section is where you make a genuine connection with visitors by going deeper into your background and experience, balancing professionalism with personality.

The code below creates a responsive About section with:

  • A prominent title with a custom underline

  • A friendly greeting with a two-column layout

  • A professional bio that highlights your expertise

Go to the About.jsx file under src/components and implement this by updating your code with the following:

//About.jsx
import React from "react";


const About = () => {
  return (
    // Main container with full width/height and background
    <div
      name="about"
      id="about"
      className="w-full h-screen bg-[#0a192f] text-gray-300"
    >
      {/*Content container with cyan background*/}
      <div className="flex flex-col justify-center items-center w-full h-full">
        {/*Title section using grid */}
        <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>
            {/*Content section with responsive grid*/}
          </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...
              </p>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};


export default About;

Click the About Me button on the landing page or refresh your browser to see your changes. The new section should display your title, greeting, and bio in a two-column layout with cyan accents.

Rendered about section

To see your changes, click the About Me button on the landing page or refresh your browser. The new section should display your title, greeting, and bio in a two-column layout with cyan accents.

How to build a Skills component

Your Skills section is where you showcase your tech stack and attract employers looking for specific expertise.

This code creates a responsive grid of technology cards with:

  • A bold, underlined title

  • An engaging introduction

  • Animated skill cards that scale on hover

  • Responsive layout (2 columns on mobile, 4 on desktop)

Go to the Skills.jsx file under src/components and implement this by updating your code with the following:

//Skills.jsx
import React from 'react';

const Skills = () => {
  return (
    // Main container with dark background
    <div name='skills' className='w-full h-screen bg-[#0a192f] text-gray-300'>
      {/* Content wrapper with max width and centering */}
      <div className='max-w-[1000px] mx-auto p-4 flex flex-col justify-center w-full h-full'>
          {/* Header section with title and intro */}
          <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> 
          {/* Skills grid - responsive layout with hover effects */}
          <div className='w-full grid grid-cols-2 sm:grid-cols-4 gap-4 text-center py-8'>
              {/* Individual skill cards with shadow and scale animation */}
              <div className='shadow-md shadow-[#040c16] hover:scale-110 duration-500'>
                  <p className='my-4'>HTML</p>
              </div>
              {/* Additional skill cards follow same pattern... */}
          </div>
      </div>
    </div>
  );
};

export default Skills;

To preview your Skills section, scroll down or click the Skills link in the navigation. You should see your tech stack displayed in an animated grid layout.

Rendered skills section

How to build a Works component

Your Works section is the proof behind your skills – it's where potential employers see your abilities in action.

The code below creates a responsive project showcase with:

  • A dynamic grid layout (2-3 columns based on screen size)

  • Project cards with hover effects revealing details

  • Demo and code links for each project

  • Clean animations for better UX

Go to the Works.jsx file under src/components and implement this by updating your code with the following:

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

const Works = () => {
  return (
    // Main container with responsive height
    <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'>
        {/* Section header */}
        <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>

        {/* Project grid */}
        <div className='grid sm:grid-cols-2 md:grid-cols-3 gap-4'>
          {/* Project card with hover overlay */}
          <div
            style={{ backgroundImage: `url(${code})` }}
            className='shadow-lg shadow-[#040c16] group container rounded-md flex justify-center items-center mx-auto content-div'
          >
            {/* Hover content */}
            <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'>Project Title</span>
              <p className='text-center'>Project description</p>
              {/* Action buttons */}
              <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>
          {/* Additional project cards follow same pattern */}
        </div>
      </div>
    </div>
  );
};

export default Works;

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

undefined

How to build a Contact component

Your Contact section is the gateway for opportunities. It makes it easy for potential clients and employers to reach out.

This code creates a clean contact form with:

  • A centered layout with custom styling

  • Input fields for name, email, and message

  • A call-to-action button with hover effects

Keep in mind this is a placeholder form. To make it fully functional, you have several options:

Email Service Integration:

  1. Set up EmailJS or a similar service.
  2. Configure the form to send emails directly.
  3. No backend is required.

Backend Integration:

  1. Create API endpoint (Node/Express).
  2. Configure form submission handling.
  3. Set up email forwarding.

Form Service:

  1. Use Formspree, Netlify Forms, or GetForm.
  2. Add service endpoint to form action.
  3. Configure email notifications.

Go to the Contact.jsx file under src/components and implement this by updating your code with the following:

//Contact.jsx
import React from 'react'

const Contact = () => {
  return (
    // Main container with full height and centering
    <div name='contact' className='w-full h-screen bg-[#0a192f] flex justify-center items-center p-4'>
        {/* Form wrapper with max width */}
        <div className='flex flex-col max-w-[600px] w-full'>
            {/* Header section */}
            <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>
            {/* Form inputs with consistent styling */}
            <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

To preview your contact form, scroll to the bottom of your portfolio or click Contact in the navigation. You'll see a centered form ready for your chosen submission method.

React portfolio contact section

How to manage your portfolio content with ButterCMS

A great portfolio website using React needs easy content management – let's upgrade from hardcoded content to a dynamic CMS solution. 

While your portfolio is functional with the static content we've added, connecting it to ButterCMS will make updates easy and give you a clean content dashboard.

Before we start the integration, you'll need to structure your content in ButterCMS.

Let's begin by setting up your ButterCMS account and modeling your portfolio content. You can set up your account by first signing up for a free account and following the prompted steps.

How to model your portfolio in ButterCMS

The sections of your React personal website will be divided into individual components that make up the page.

Modeling 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:

The component picker will allow you to select the different components you want and omit the ones you don't need. Take the following steps:

  • Click the "Add your first field" button.

  • Select Component Picker from the left menu.

  • This creates a flexible container for all portfolio sections.

Creating a component picker in ButterCMS for the portfolio page.

Modeling 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.

Why do it like this?

Since your homepage displays a bold headline and detailed introduction paragraph, we'll use Long Text fields for both "landing caption" and "landing main text." Long Text gives you the formatting flexibility you need. We can update our portfolio content by mapping these fields to Butter without touching the code. 

Modeling the portfolio’s 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.

Why do it like this?

Think of these fields as the CMS version of your React code.  Since our About caption in our React code is short, and we don't anticipate it exceeding one line, we can select the Short Text field. The main details will most likely exceed one line, so we'll select the Long Text field.

Modeling 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.

Why a Repeater? Think of it as your skills array in CMS form. Instead of hardcoding ["React," "Node," "JavaScript"] in your component, you can add, remove, or update skills through ButterCMS - perfect for when you learn new technologies. 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.

Creating the Portfolio page and adding our 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: 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.

Connecting your portfolio 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.

// App.js with API connection and props passing
//...
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:

// Maps landing_caption and landing_main_text
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:

// Maps about_caption and about_main_details
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:

// Maps skill_header and skills array
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:

// Maps work_header and works array
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.

React portfolio websites you should take inspiration from

When looking at other developers' portfolios, focus on what makes each unique rather than copying their exact style. Think about:

First impressions:

  • How quickly can you understand what they do?

  • Does the design match their expertise?

  • What grabs your attention first?

Content organization:

  • How do they tell their story?

  • Where do they place key information?

  • How do they showcase projects?

Technical execution:

  • What interactions feel smooth?

  • How does it perform on mobile?

  • Which features actually enhance the experience?

Now that you’ve learned how to assess a portfolio, take a look at some solid portfolio projects from top-tier React professionals to get an idea of what you can do.

Brittany Chiang

Brittany Chiang Portfolio

Clean architecture, smooth transitions, and excellent project showcasing. Notice how the minimalist design lets the content shine.

Josh W Comeau 

Josh C portfolio

Unique interactive elements that demonstrate technical skill while remaining playful. Pay attention to how animations enhance usability.

Kent C. Dodds 

Kent Dodd portfolio

The perfect balance of personal brand and technical expertise. Note how content hierarchy guides visitors naturally.

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’re in a hurry

Building a portfolio can be complex –starting with a template lets you focus on customization and content while maintaining professional architecture. Here are three well-structured options:

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! Building a portfolio website with React isn’t as hard as you imagined.

To recap: In this React portfolio website tutorial, you learned how to build a React website, set up a content structure for it on ButterCMS, and retrieve the content for your application.

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

Check out the documentation to learn more about using ButterCMS for your websites.

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!