In today’s digital landscape, a personal portfolio website is more than just a digital resume; it’s your online identity. It’s where you showcase your skills, projects, and personality to potential employers, clients, or collaborators. A well-designed portfolio can make a significant difference in how you’re perceived and the opportunities that come your way. This tutorial will guide you through building a simple, yet effective, portfolio website using Next.js, a powerful React framework for building modern web applications.
Why Next.js?
Choosing the right tools is crucial for any project. Next.js offers several advantages that make it an excellent choice for building a portfolio website:
- Server-Side Rendering (SSR) and Static Site Generation (SSG): Next.js allows you to pre-render your website, improving SEO and initial load times. This is especially important for portfolio websites, where fast loading speeds are essential for a good user experience.
- Built-in Routing: Next.js simplifies routing, making it easy to navigate between different sections of your portfolio.
- Image Optimization: Next.js provides built-in image optimization, automatically resizing and compressing images for optimal performance.
- Developer Experience: Next.js offers a great developer experience with features like hot module replacement and easy deployment.
By using Next.js, you can create a fast, SEO-friendly, and user-friendly portfolio website that will make a great impression.
Project Overview
In this tutorial, we will build a simple portfolio website with the following sections:
- Home: A brief introduction about yourself.
- About: A more detailed description of your skills, experience, and background.
- Projects: A showcase of your projects with links and descriptions.
- Contact: A contact form or links to your social media profiles.
We’ll keep the design clean and modern, focusing on showcasing your work effectively. This project is designed for beginners to intermediate developers, so we’ll break down each step with clear explanations and code examples.
Prerequisites
Before we begin, make sure you have the following installed:
- Node.js and npm (or yarn): You’ll need Node.js and npm (Node Package Manager) or yarn installed on your system. You can download them from nodejs.org.
- A Code Editor: A code editor like VS Code, Sublime Text, or Atom is recommended.
- Basic knowledge of HTML, CSS, and JavaScript: Familiarity with these languages is necessary to understand the code.
Setting Up the Project
Let’s start by creating a new Next.js project. Open your terminal and run the following command:
npx create-next-app my-portfolio
This command will create a new Next.js project named “my-portfolio”. Navigate into the project directory:
cd my-portfolio
Now, let’s install some dependencies we’ll use for styling and other features. For this tutorial, we’ll use Tailwind CSS for styling.
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
This installs the necessary packages and generates the `tailwind.config.js` and `postcss.config.js` files. Next, configure Tailwind CSS by adding the paths to all of your template files in your `tailwind.config.js` file. Replace the content of the file with the following:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./app/**/*.{js,ts,jsx,tsx,mdx}',
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
// Or if using `src` directory:
'./src/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {
// Add your custom styles here
},
},
plugins: [],
}
Next, add the Tailwind directives to your global stylesheet. Open `src/app/globals.css` (or the equivalent file in your project) and add the following directives at the top of the file:
@tailwind base;
@tailwind components;
@tailwind utilities;
With Tailwind configured, you can start using its utility classes in your components. Let’s start by cleaning up the default `app/page.js` file. Replace the content with a basic structure:
// src/app/page.js
import React from 'react';
export default function Home() {
return (
<div className="container mx-auto p-4">
<h1 className="text-2xl font-bold mb-4">Welcome to My Portfolio</h1>
<p>This is a simple portfolio website built with Next.js.</p>
</div>
);
}
This creates a basic “Hello World” page using Tailwind CSS for styling. You can start the development server by running:
npm run dev
Open your browser and go to `http://localhost:3000` to see your portfolio website. You should see the heading and paragraph you just added.
Creating Components
To keep our code organized and reusable, let’s create separate components for each section of our portfolio. Create a `components` directory inside the `src` folder. Inside the `components` directory, create the following files:
- Navbar.js: For the navigation bar.
- Hero.js: For the home section.
- About.js: For the about section.
- Projects.js: For the projects section.
- Contact.js: For the contact section.
Let’s start with the `Navbar.js` component:
// src/components/Navbar.js
import Link from 'next/link';
const Navbar = () => {
return (
<nav className="bg-white shadow-md p-4">
<div className="container mx-auto flex justify-between items-center">
<Link href="/" className="text-xl font-bold">
Your Name
</Link>
<ul className="flex space-x-6">
<li><Link href="/">Home</Link></li>
<li><Link href="/about">About</Link></li>
<li><Link href="/projects">Projects</Link></li>
<li><Link href="/contact">Contact</Link></li>
</ul>
</div>
</nav>
);
};
export default Navbar;
This component creates a navigation bar with links to different sections. We use the `Link` component from `next/link` for client-side navigation. Now, let’s create the `Hero.js` component:
// src/components/Hero.js
const Hero = () => {
return (
<section className="bg-gray-100 py-20">
<div className="container mx-auto text-center">
<h2 className="text-4xl font-bold mb-4">Hello, I'm Your Name</h2>
<p className="text-lg">I'm a [Your Profession] specializing in [Your Specialization].</p>
</div>
</section>
);
};
export default Hero;
This component displays a welcome message and a brief introduction. Next, create the `About.js` component:
// src/components/About.js
const About = () => {
return (
<section className="py-12">
<div className="container mx-auto">
<h3 className="text-3xl font-bold mb-6">About Me</h3>
<p className="mb-4">Write a brief description of your skills, experience, and background here.</p>
<ul className="list-disc list-inside">
<li>Skill 1</li>
<li>Skill 2</li>
<li>Skill 3</li>
</ul>
</div>
</section>
);
};
export default About;
This component provides a more detailed description of yourself. Now, let’s create the `Projects.js` component:
// src/components/Projects.js
const Projects = () => {
return (
<section className="py-12 bg-gray-100">
<div className="container mx-auto">
<h3 className="text-3xl font-bold mb-6">Projects</h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div className="bg-white rounded-lg shadow-md p-4">
<h4 className="text-xl font-bold mb-2">Project 1</h4>
<p className="text-gray-700 mb-2">Brief description of project 1.</p>
<a href="#" className="text-blue-500 hover:underline">View Project</a>
</div>
<div className="bg-white rounded-lg shadow-md p-4">
<h4 className="text-xl font-bold mb-2">Project 2</h4>
<p className="text-gray-700 mb-2">Brief description of project 2.</p>
<a href="#" className="text-blue-500 hover:underline">View Project</a>
</div>
<div className="bg-white rounded-lg shadow-md p-4">
<h4 className="text-xl font-bold mb-2">Project 3</h4>
<p className="text-gray-700 mb-2">Brief description of project 3.</p>
<a href="#" className="text-blue-500 hover:underline">View Project</a>
</div>
</div>
</div>
</section>
);
};
export default Projects;
This component showcases your projects. Finally, create the `Contact.js` component:
// src/components/Contact.js
const Contact = () => {
return (
<section className="py-12">
<div className="container mx-auto">
<h3 className="text-3xl font-bold mb-6">Contact Me</h3>
<p className="mb-4">Feel free to reach out!</p>
<ul className="space-y-2">
<li>Email: <a href="mailto:your.email@example.com" className="text-blue-500 hover:underline">your.email@example.com</a></li>
<li>LinkedIn: <a href="#" className="text-blue-500 hover:underline">Your LinkedIn Profile</a></li>
<li>GitHub: <a href="#" className="text-blue-500 hover:underline">Your GitHub Profile</a></li>
</ul>
</div>
</section>
);
};
export default Contact;
This component provides contact information. Now, in the `app/page.js` file, import these components and use them to build the home page:
// src/app/page.js
import Navbar from '../components/Navbar';
import Hero from '../components/Hero';
import About from '../components/About';
import Projects from '../components/Projects';
import Contact from '../components/Contact';
export default function Home() {
return (
<div>
<Navbar />
<Hero />
<About />
<Projects />
<Contact />
</div>
);
}
This sets up the basic structure of your homepage using the components we created. You can now see the components rendered on the home page.
Creating Pages and Routing
Next.js makes it easy to create different pages. Create the following files inside the `app` directory:
- about/page.js: For the about page.
- projects/page.js: For the projects page.
- contact/page.js: For the contact page.
In `app/about/page.js`, import the `About` component and render it:
// src/app/about/page.js
import Navbar from '../../components/Navbar';
import About from '../../components/About';
export default function AboutPage() {
return (
<div>
<Navbar />
<About />
</div>
);
}
In `app/projects/page.js`, import the `Projects` component and render it:
// src/app/projects/page.js
import Navbar from '../../components/Navbar';
import Projects from '../../components/Projects';
export default function ProjectsPage() {
return (
<div>
<Navbar />
<Projects />
</div>
);
}
In `app/contact/page.js`, import the `Contact` component and render it:
// src/app/contact/page.js
import Navbar from '../../components/Navbar';
import Contact from '../../components/Contact';
export default function ContactPage() {
return (
<div>
<Navbar />
<Contact />
</div>
);
}
Now, you can navigate between these pages using the links in the `Navbar` component. Clicking on the links will take you to the respective pages.
Adding Project Details (Dynamic Routes)
To display detailed information about each project, you can use dynamic routes. Create a new folder structure inside the `app/projects` directory:
- app/projects/[slug]/page.js
The `[slug]` part is a dynamic segment that represents the project’s unique identifier (e.g., project-1, project-2). Create a sample data file, for example, `data/projects.js`:
// data/projects.js
export const projects = [
{
slug: 'project-1',
title: 'Project 1 Title',
description: 'Detailed description of project 1.',
link: '#',
},
{
slug: 'project-2',
title: 'Project 2 Title',
description: 'Detailed description of project 2.',
link: '#',
},
{
slug: 'project-3',
title: 'Project 3 Title',
description: 'Detailed description of project 3.',
link: '#',
},
];
Now, in `app/projects/[slug]/page.js`, import the `projects` data and use the `params` object to get the slug and display the project details:
// src/app/projects/[slug]/page.js
import { projects } from '../../data/projects';
import Navbar from '../../../components/Navbar';
export default function ProjectDetail({ params }) {
const project = projects.find((project) => project.slug === params.slug);
if (!project) {
return <div>Project not found</div>;
}
return (
<div>
<Navbar />
<div className="container mx-auto py-12">
<h2 className="text-3xl font-bold mb-4">{project.title}</h2>
<p className="mb-4">{project.description}</p>
<a href={project.link} className="text-blue-500 hover:underline">View Project</a>
</div>
</div>
);
}
Update the `Projects` component (`src/components/Projects.js`) to link to these dynamic project detail pages:
// src/components/Projects.js
import Link from 'next/link';
import { projects } from '../../data/projects';
const Projects = () => {
return (
<section className="py-12 bg-gray-100">
<div className="container mx-auto">
<h3 className="text-3xl font-bold mb-6">Projects</h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{projects.map((project) => (
<div key={project.slug} className="bg-white rounded-lg shadow-md p-4">
<h4 className="text-xl font-bold mb-2">{project.title}</h4>
<p className="text-gray-700 mb-2">{project.description}</p>
<Link href={`/projects/${project.slug}`} className="text-blue-500 hover:underline">
View Project
</Link>
</div>
))}
</div>
</div>
</section>
);
};
export default Projects;
Now, each project card will link to its corresponding detail page. When you click on a project, it will display the details based on its slug.
Adding a Contact Form (Advanced)
While a full contact form with backend functionality is beyond the scope of this beginner tutorial, we can create a basic form that you can customize later. In your `Contact.js` component, replace the contact information with a form:
// src/components/Contact.js
const Contact = () => {
return (
<section className="py-12">
<div className="container mx-auto">
<h3 className="text-3xl font-bold mb-6">Contact Me</h3>
<form className="space-y-4">
<div>
<label htmlFor="name" className="block text-sm font-medium text-gray-700">
Name
</label>
<input
type="text"
id="name"
name="name"
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
/>
</div>
<div>
<label htmlFor="email" className="block text-sm font-medium text-gray-700">
Email
</label>
<input
type="email"
id="email"
name="email"
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
/>
</div>
<div>
<label htmlFor="message" className="block text-sm font-medium text-gray-700">
Message
</label>
<textarea
id="message"
name="message"
rows="4"
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
></textarea>
</div>
<button
type="submit"
className="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Submit
</button>
</form>
</div>
</section>
);
};
export default Contact;
This adds a simple form with name, email, and message fields. You’ll need to implement the backend logic to handle form submissions (e.g., using a service like Formspree or building your own API endpoint) to make this form functional.
Deployment
Once you’ve finished building your portfolio, you’ll need to deploy it to a hosting platform. Here are a few popular options:
- Vercel: Vercel is the recommended platform for deploying Next.js applications. It provides a simple and fast deployment process.
- Netlify: Netlify is another excellent option for deploying static sites and web applications.
- Other Platforms: You can also deploy to platforms like AWS, Google Cloud, or Heroku.
To deploy to Vercel, simply push your code to a Git repository (e.g., GitHub, GitLab, or Bitbucket) and import the repository into Vercel. Vercel will automatically detect that it’s a Next.js project and handle the deployment process for you.
Common Mistakes and How to Fix Them
- Incorrect File Paths: Make sure your file paths in import statements are correct. Double-check the directory structure.
- Typographical Errors: Typos in component names, variable names, or CSS class names can cause errors.
- Missing Dependencies: Ensure you’ve installed all the necessary dependencies using npm or yarn.
- CSS Issues: If your styles aren’t applying, check your Tailwind configuration and ensure you’ve included the necessary directives in your global CSS file.
- Routing Errors: If your routes aren’t working, verify your file structure in the `app` directory and that you’re using the `Link` component correctly.
Key Takeaways
- Next.js is a powerful framework for building modern, SEO-friendly portfolio websites.
- Components help keep your code organized and reusable.
- Routing is simplified with Next.js, making it easy to create different pages.
- Dynamic routes allow you to create detailed project pages.
- Deployment is straightforward with platforms like Vercel.
FAQ
- Can I use a different CSS framework instead of Tailwind CSS?
Yes, you can use any CSS framework you prefer, such as Bootstrap, Material UI, or Styled Components. The key is to include the necessary CSS files and use the appropriate classes in your components.
- How can I add images to my portfolio?
You can use the `Image` component provided by Next.js for optimized image loading and resizing. Import the `Image` component from ‘next/image’ and use it to display your images. Make sure to optimize your images for web use before uploading them.
- How do I handle form submissions?
For form submissions, you’ll typically need a backend solution. You can either use a third-party service like Formspree or build your own API endpoint. The form data is sent to the backend, which processes it (e.g., sending an email or saving the data to a database).
- How do I make my portfolio responsive?
Tailwind CSS makes it easy to create responsive designs using utility classes. You can add prefixes like `md:`, `lg:`, and `xl:` to your classes to apply different styles at different screen sizes. For example, `md:grid-cols-2` will apply the `grid-cols-2` style on medium-sized screens and larger.
- Where can I find more Next.js resources?
The official Next.js documentation at nextjs.org/docs is an excellent resource. You can also find many tutorials, articles, and community forums online.
Building a portfolio website with Next.js is a rewarding project that allows you to showcase your skills and create a strong online presence. By following these steps, you can create a professional-looking portfolio that highlights your work. Remember to customize the content, add your own projects, and refine the design to reflect your personal brand. The journey of building your portfolio is also a great opportunity to learn and improve your skills in web development. With a little effort, your portfolio can become a powerful tool for your career.
