This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- @vitejs/plugin-react uses Babel for Fast Refresh
- @vitejs/plugin-react-swc uses SWC for Fast Refresh
This guide will walk you through creating a professional portfolio website using React, TypeScript, Vite, and Tailwind CSS. These technologies represent the modern approach to web development, combining powerful frameworks with developer-friendly tools.
Think of this stack as your toolkit for building a house - React provides the structure, TypeScript ensures quality, Vite speeds up the construction, and Tailwind CSS handles the styling.
Vite (French for "quick") is a build tool that significantly speeds up development with near-instant hot module replacement.
# Create a new React project with TypeScript template
npm create vite@latest my-portfolio -- --template react-ts
# Navigate to the project folder
cd my-portfolio
# Install core dependencies
npm installThis creates your project foundation with all the necessary files to get started quickly.
# Install React Router for navigation
npm install react-router-dom react-router
# Install Tailwind CSS and its dependencies
npm install -D tailwindcss postcss autoprefixer
# Initialize Tailwind CSS
npx tailwindcss init -pThese commands add the ability to navigate between pages and to style your website using utility classes.
Create multiple configuration files for different parts of your project:
tsconfig.json- The root configurationtsconfig.app.json- For your application codetsconfig.node.json- For build scripts
Enable strict type checking to catch errors early:
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": trueTypeScript helps you write safer code by catching errors before they reach the browser.
/src
/assets # Images, SVGs, and other static files
/components # Reusable UI components
/pages # Full page components
/Routes # Routing configuration
A well-organized project structure makes it easier to find files and understand how they relate to each other.
Create a Routes.tsx file to define your navigation paths:
import { createBrowserRouter } from "react-router-dom";
import App from "../App";
import Home from "../pages/HomePage/home";
import About from "../pages/AboutPage/about";
export const router = createBrowserRouter([
{
path: "/",
element: <App />,
children: [
{ path: "", element: <Home /> },
{ path: "about", element: <About /> }
]
}
]);This creates a map of your website, telling React what component to show when a user visits a specific URL.
Update your main.tsx to use the router:
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import { RouterProvider } from 'react-router-dom'
import { router } from "./Routes/Routes"
const rootElement = document.getElementById('root');
if (!rootElement) {
throw new Error('Root element not found');
}
createRoot(rootElement).render(
<StrictMode>
<RouterProvider router={router} />
</StrictMode>,
)This connects your routing system to your React application and mounts it to the HTML document.
The App.tsx file serves as your main layout template:
function App() {
return (
<div className="flex flex-col min-h-screen">
<header>
{/* Navigation */}
<nav>
<Link to="/">My Portfolio</Link>
<Link to="/about">About/Contact</Link>
</nav>
</header>
<main className="flex-grow">
{/* This is where page components will be rendered */}
<Outlet />
</main>
<footer>
© {new Date().getFullYear()} Your Name
</footer>
</div>
)
}The App component is like the frame of a house - it provides consistent structure while the interior (content) changes.
Create a Card.tsx component for displaying projects:
interface CardProps {
title: string;
date: string;
imgpath?: string; // Optional with default
description?: string; // Optional
}
export default function Card({
title,
date,
imgpath = "/placeholder.jpg",
description
}: CardProps) {
return (
<div className="bg-white rounded-lg shadow-md overflow-hidden">
<img src={imgpath} alt={title} className="w-full h-48 object-cover" />
<div className="p-4">
<h2 className="font-bold">{title}</h2>
<p className="text-gray-500">{date}</p>
{description && <p>{description}</p>}
</div>
</div>
)
}Think of this component as a template for business cards - you define the design once, then simply fill in different information for each project.
export default function Home() {
const projects = [
{
id: 1,
title: 'Project One',
date: 'January 2023',
description: 'Project description here'
},
// More projects...
];
return (
<div>
<h1>My Projects</h1>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{projects.map(project => (
<Card
key={project.id}
title={project.title}
date={project.date}
description={project.description}
/>
))}
</div>
</div>
)
}The home page displays your projects in a grid layout, with each project represented by a Card component.
export default function About() {
return (
<div>
<h1>About Me</h1>
<p>Personal information and skills...</p>
<h2>Contact</h2>
<ul>
<li>Email: [email protected]</li>
<li>LinkedIn: linkedin.com/in/yourname</li>
</ul>
</div>
)
}The about page provides information about you and your contact details.
React uses a component-based architecture where small, reusable components are combined to create complex interfaces.
// Example of component composition
<App>
<Home>
<Card />
<Card />
<Card />
</Home>
</App>This is like building with LEGO blocks - small pieces combined to create something complex.
Define the shape of your component props with TypeScript:
// Define the shape of data
interface Project {
id: number;
title: string;
date: string;
imgpath?: string;
description?: string;
}
// Use the interface
const projects: Project[] = [
{ id: 1, title: 'Project One', date: '2023' },
// More projects...
];TypeScript interfaces are like blueprints - they define exactly what properties an object should have.
Transform arrays of data into arrays of components:
{projects.map(project => (
<Card
key={project.id}
title={project.title}
date={project.date}
description={project.description}
/>
))}This is like having a template and applying it to each item in a list automatically.
React hooks let you use state and other React features in functional components:
import { useEffect } from 'react';
function App() {
useEffect(() => {
// Code that runs when the component mounts
document.title = 'My Portfolio';
// Optional cleanup function
return () => {
// Code that runs when component unmounts
};
}, []); // Empty array means "run only once on mount"
// Rest of component...
}Hooks are special functions that let you "hook into" React features. They're like power tools for your components.
Update your tailwind.config.js:
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}"
],
theme: {
extend: {
// Custom colors, fonts, etc.
},
},
plugins: [],
}Add the Tailwind directives to your CSS:
/* src/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;This tells Tailwind to scan your files for class names and generate the necessary CSS.
Style your components directly with utility classes:
<div className="max-w-sm bg-white rounded-lg shadow-md overflow-hidden">
<img className="w-full h-48 object-cover" src="image.jpg" alt="Project" />
<div className="p-4">
<h2 className="text-xl font-bold text-gray-800">Title</h2>
</div>
</div>Utility classes are like small styling building blocks - instead of writing CSS separately, you apply styles directly in your HTML.
Use breakpoint prefixes for responsive layouts:
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{/* Content */}
</div>grid-cols-1: One column on small screensmd:grid-cols-2: Two columns on medium screenslg:grid-cols-3: Three columns on large screens
This makes your site automatically adjust its layout for different screen sizes.
# Initialize a new Git repository
git init
# Add all files to staging
git add .
# Commit your changes
git commit -m "Initial commit"This creates a record of your project that you can track over time.
# Create a new repository on GitHub first, then:
git remote add origin https://github.com/yourusername/your-repo.git
# Push your code to GitHub
git push -u origin mainThis connects your local project to GitHub so you can share your code and collaborate with others.
# Create a new branch for a feature
git checkout -b feature/new-component
# After making changes, commit them
git add .
git commit -m "Add new component"
# Switch back to main branch
git checkout main
# Merge your changes
git merge feature/new-componentBranches let you work on features separately without affecting the main codebase.
Add a build script to your package.json:
"scripts": {
"build": "tsc -b && vite build"
}Run the build command:
npm run buildThis creates optimized files ready for deployment.
Install the GitHub Pages package:
npm install --save-dev gh-pagesAdd deployment scripts to package.json:
"homepage": "https://yourusername.github.io/your-repo",
"scripts": {
"predeploy": "npm run build",
"deploy": "gh-pages -d dist"
}Update vite.config.ts to support GitHub Pages:
export default defineConfig({
plugins: [react()],
base: '/your-repo-name/',
})This configures your project to work properly when hosted on GitHub Pages.
Update your router to work with the base path:
createBrowserRouter([
// Routes...
], {
basename: '/your-repo-name'
})This ensures your navigation works correctly when deployed to a subdirectory.
Run the deploy command:
npm run deployThis builds your project and publishes it to GitHub Pages.
- Single Responsibility: Each component should do one thing well
- Reusability: Design components to be used in multiple places
- Props vs. State: Use props for data passed to components, state for data that changes
Following these principles makes your code easier to maintain and extend.
- Use React's
memo,useMemo, anduseCallbackfor expensive operations - Split your code into smaller chunks that load on demand
- Optimize images and other assets
These techniques make your website faster and more responsive.
- Group related files together
- Use consistent naming conventions
- Keep components small and focused
Good organization makes it easier for you (and others) to navigate and understand your code.
- Catch errors during development instead of at runtime
- Better autocompletion and documentation
- Clearer interfaces between components
TypeScript might seem intimidating at first, but it saves time in the long run by preventing bugs.
- React and its ecosystem evolve quickly
- Follow blogs, tutorials, and documentation
- Experiment with new features and patterns
Web development is always changing - the best developers are those who keep learning.
Building a React portfolio is not just about showcasing your projects - it's also a project itself that demonstrates your skills with modern web technologies. By following this guide, you've created a professional, responsive website that shows off both your work and your development abilities.
Remember that this is just the beginning. You can extend your portfolio with animations, dark mode, blog functionality, or any other features that showcase your unique skills and personality.