2026-01-305 min read

Building a Modern Portfolio with React Router v7 and Tailwind 4

ReactTailwind CSSWeb Development

Introduction

Building a portfolio website is a rite of passage for many developers. It's a chance to showcase your skills, experiment with new technologies, and create something that represents you professionally. In this post, I'll share my experience building this portfolio using React Router v7 and Tailwind CSS v4.

Why React Router v7?

React Router v7 brings some exciting changes to the table:

  • File-based routing - Routes are automatically generated based on your file structure
  • Built-in data loading - The loader function makes data fetching seamless
  • Type safety - Better TypeScript integration with useLoaderData
  • Server-side rendering - Out of the box SSR support

Here's an example of how I set up a route with data loading:

typescript
export async function loader({ params }: LoaderFunctionArgs) {
  const project = getProjectBySlug(params.slug);
  if (!project) {
    throw new Response('Not found', { status: 404 });
  }
  return { project };
}

Tailwind CSS 4: What's New?

Tailwind CSS v4 introduced several improvements:

1. CSS-first Configuration

Instead of JavaScript configuration, Tailwind 4 uses CSS for theming:

css
@theme {
  --font-sans: "Inter", "system-ui", "sans-serif";
  --color-primary: #3B82F6;
}

2. Dynamic Theming

I implemented a theme system that allows users to switch between Brown and Pink themes:

css
[data-theme="brown"] {
  --bg-primary: #dedbca;
  --bg-secondary: #6E5034;
  --text-primary: #000;
}

[data-theme="pink"] {
  --bg-primary: oklch(93.6% 0.032 17.717);
  --bg-secondary: #ffa1a3;
  --text-primary: #000;
}

Key Features

Dynamic Theme Switching

Users can choose between Brown and Pink themes, with their preference saved to localStorage:

typescript
const setTheme = (newTheme: Theme) => {
  setThemeState(newTheme);
  localStorage.setItem('theme', newTheme);
};

Markdown Blog System

The blog system uses gray-matter for frontmatter parsing and marked for Markdown rendering with syntax highlighting powered by highlight.js.

Responsive Design

Every component is designed mobile-first, ensuring a great experience on all devices.

Lessons Learned

  1. Start with theming - Setting up CSS variables early makes styling consistent
  2. Use semantic HTML - It improves accessibility and SEO
  3. Keep components small - Easier to maintain and test

What's Next?

I'm planning to add:

  • Dark mode support
  • Blog search functionality
  • Project filtering by technology

Thanks for reading! Feel free to explore the portfolio and reach out if you have any questions.