Skip to main content
Early access — new tools and guides added regularly
🔵 Build Real Projects — Guide 20 of 22
View track
>_ claude codeIntermediate25 min

Build a Portfolio Website

Build a professional portfolio website with responsive design, dark mode, project showcases, a contact form, and smooth animations.

What you will build
A deployable portfolio website with project showcase, about section, and contact form

Planning the portfolio structure

A portfolio website has one job: convince visitors you are good at what you do. Every design decision should serve that goal. The structure is simple: a hero section with your name and headline, a projects section showcasing your best work, an about section with your background, a skills section showing your expertise, and a contact section making it easy to reach you. Ask Claude Code: Create a Next.js project with TypeScript and Tailwind for a portfolio website. Set up the fonts — use a serif font for headings (like Fraunces or Playfair Display) and a clean sans-serif for body text (like DM Sans or Inter). Define colour tokens in tailwind.config: a primary brand colour, a secondary accent, neutral greys, and separate light and dark mode palettes. Create the data model at src/data/portfolio.ts. Ask Claude Code: Define TypeScript types for: Project (id, title, slug, description, longDescription, image, technologies as array of strings, liveUrl optional, githubUrl optional, featured boolean, year), Skill (name, category as frontend or backend or tools or design, proficiency as percentage), Experience (company, role, startDate, endDate optional, description, highlights as array of strings), and PersonalInfo (name, title, tagline, bio, email, socialLinks). Populate with placeholder data that demonstrates the layout — you will replace it with your real information later. The data-driven approach means changing your portfolio content is just editing a data file, not restructuring components.

Hero section and navigation

The hero section is the first thing visitors see — it must communicate who you are and what you do within three seconds. Ask Claude Code: Create a hero section component with a large heading showing your name, a subtitle showing your professional title (like Full-Stack Developer or Product Designer), a one-sentence tagline that captures your unique value, and two CTA buttons — View My Work (scrolls to projects) and Get in Touch (scrolls to contact). Add a subtle animated background — not distracting, but enough to make the page feel alive. Options include a gradient that slowly shifts colours, floating geometric shapes, or a grid pattern with a subtle parallax effect on mouse movement. Ask Claude Code: Add a smooth parallax background to the hero using CSS transforms triggered by mouse position. Keep the animation subtle — no more than 10 pixels of movement. Disable on mobile to save battery and avoid motion sickness issues. Build the navigation. Ask Claude Code: Create a sticky navigation bar that appears after scrolling past the hero section. Include links to each section (Projects, About, Skills, Contact) that smooth-scroll to the target. Highlight the currently visible section in the nav as the user scrolls (intersection observer). On mobile, collapse to a hamburger menu with a full-screen overlay. Add a theme toggle button in the nav for dark/light mode. The navigation should feel invisible until needed. Transparent background when at the top of the page, solid background with a subtle shadow when scrolled. Ask Claude Code: Implement the scroll-aware navigation styling. Transparent on top, solid on scroll, with a smooth transition between states. Common error: smooth scrolling with hash links can conflict with Next.js routing. Use scrollIntoView with behavior: 'smooth' instead of hash links for in-page navigation.

Project showcase with filtering

The projects section is the core of your portfolio — it proves your skills with evidence. Ask Claude Code: Create a projects grid that displays project cards in a responsive layout. Two columns on mobile, three on desktop. Each card shows: a project screenshot (with hover zoom effect), the project title, a short description (two lines maximum), technology tags as small pills, and buttons for Live Demo and Source Code. Featured projects should be larger — spanning two columns — with additional detail visible. Add project filtering. Ask Claude Code: Create filter buttons above the grid for All, Frontend, Backend, Full-Stack, and Mobile (or whatever categories match your work). Clicking a filter animates the grid — matching projects fade in and slide into position while non-matching projects fade out. Use CSS transitions for the animation. Create individual project pages. Ask Claude Code: Build a dynamic route at src/app/projects/[slug]/page.tsx. Each project page shows: a large hero image or screenshot gallery, the full project description with rich text formatting, a technical details section listing the technology stack with brief explanations of why each technology was chosen, links to the live site and source code, and a Next/Previous navigation to browse between projects. Add a screenshot gallery with lightbox. Ask Claude Code: If a project has multiple screenshots, show them as a row of thumbnails. Clicking a thumbnail opens a full-screen lightbox overlay with left/right navigation, keyboard arrow support, and swipe gestures on mobile. Close with Escape or clicking outside the image. Common error: large project images slow the page dramatically. Use Next.js Image with quality set to 75, proper sizing, and lazy loading for images below the fold. Only the first two project images should load eagerly.

About, skills, and experience sections

The about section humanises your portfolio — visitors want to work with a person, not a skill list. Ask Claude Code: Create an about section with a two-column layout. Left column: a professional photo (use a placeholder for now) with a subtle border or shadow. Right column: a brief bio (3 to 4 paragraphs) written in first person, covering your background, what drives you, and what you are looking for. Below the bio, show social links as icon buttons (GitHub, LinkedIn, Twitter, email). Build the skills section as a visual display. Ask Claude Code: Create a skills grid grouped by category (Frontend, Backend, Tools, Design). Each skill shows its name and a horizontal bar indicating proficiency (animated from 0 to the proficiency percentage when scrolled into view using intersection observer). Use colour coding per category. Add technology logos next to each skill name using simple SVG icons or text labels. Avoid subjective skill ratings — a bar showing 80% in React and 60% in Vue suggests a precision that skill self-assessment does not have. Consider replacing percentage bars with simple groupings: Expert, Proficient, and Familiar. Ask Claude Code: Create an alternative skills display using a tag cloud where skill names are sized by proficiency — larger text for expert skills, medium for proficient, smaller for familiar. Let me toggle between the bar chart view and the tag cloud view. Build the experience timeline. Ask Claude Code: Create a vertical timeline component for work experience. Each entry shows the company name, your role, the date range, and key highlights as bullet points. The timeline line runs down the left side with dots marking each position. Alternate entries left and right on desktop for visual interest. On mobile, all entries align to the right of the timeline. Animate entries in as the user scrolls — each entry fades in and slides up when it enters the viewport.

Contact form and social integration

Make it effortless for visitors to reach you. Ask Claude Code: Create a contact section with a form and a sidebar. The form has fields for name, email, subject (dropdown with options like Job Opportunity, Freelance Project, Collaboration, Other), and message. Add proper validation — email format, required fields, minimum message length of 20 characters. The sidebar shows alternative contact methods: email address (with a copy-to-clipboard button), LinkedIn profile link, GitHub profile link, and your timezone with current local time. For form submission without a backend, use a service like Formspree, Web3Forms, or a Next.js API route that sends email via Resend. Ask Claude Code: Set up form submission using Resend. Create an API route at src/app/api/contact/route.ts that receives the form data, validates it on the server, sends an email to your address with the form contents, and returns a success or error response. Add rate limiting — maximum 3 submissions per IP per hour. After successful submission, show a thank-you message with an estimated response time. Ask Claude Code: Add a thank-you state to the contact form. After submission, replace the form with a confirmation message: Thanks for reaching out. I typically respond within 24 hours. Include a button to send another message. Add spam protection. Ask Claude Code: Implement a honeypot field — a hidden input that real users never see or fill in, but bots fill automatically. If the honeypot field has a value, silently reject the submission without showing an error. Also add a time-based check: reject submissions that arrive less than 3 seconds after the page loaded, since humans cannot fill a form that fast. Common error: if emails are not sending in production, check that your Resend API key is set as an environment variable on your hosting platform and that your sending domain is verified.

Dark mode, animations, and deployment

A polished portfolio needs dark mode support and thoughtful animations. Ask Claude Code: Implement dark mode using Tailwind's dark variant and class-based toggling. Detect the system preference on first visit (prefers-color-scheme media query). Store the user's manual choice in localStorage. Toggle with a button in the navigation — use a sun icon for light mode and a moon icon for dark mode. Ensure every element has appropriate dark mode colours: backgrounds, text, borders, code blocks, images (add a subtle brightness filter in dark mode so white-background screenshots do not blind the user). Add scroll-triggered animations. Ask Claude Code: Use intersection observer to trigger animations when elements scroll into view. The hero text should fade in and slide up on page load. Project cards should stagger their fade-in (first card appears, then second 100ms later, then third). Skills bars should animate from zero to their target width. Timeline entries should slide in from the left or right. All animations should respect the prefers-reduced-motion media query — if the user has enabled reduced motion in their system settings, skip all animations and show elements immediately. Add a page transition effect. Ask Claude Code: When navigating between pages (like clicking a project card to its detail page), add a smooth fade transition. Use Next.js page transitions with CSS animations. Keep transitions short — 200 to 300 milliseconds maximum. Deploy to Vercel with a custom domain. Ask Claude Code: Configure the project for Vercel. Set up a custom domain, add meta tags for SEO (title, description, Open Graph image for social sharing), create a favicon, and generate a sitemap. Test with Lighthouse — target 95 or above on all four metrics. Share the deployed URL on LinkedIn and GitHub as your new portfolio. Run the entire site through a screen reader to verify accessibility. Ask Claude Code: Run a final accessibility audit. Check colour contrast ratios in both light and dark mode, verify all images have alt text, ensure keyboard navigation works on every interactive element, and test the contact form with a screen reader.

Related Lesson

Web Design Principles

This guide is hands-on and practical. The full curriculum covers the conceptual foundations in depth with structured lessons and quizzes.

Go to lesson