Bookmark
React App Template
src/index.css
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
/* Light theme */
--color-background: #ffffff;
--color-background-soft: #f8fafc;
--color-background-mute: #f1f5f9;
--color-border: #e2e8f0;
--color-border-hover: #cbd5e1;
--color-heading: #1e293b;
--color-text: #475569;
--color-text-soft: #64748b;
--color-primary: #3b82f6;
--color-primary-hover: #2563eb;
--color-primary-soft: #dbeafe;
--color-secondary: #6366f1;
--color-success: #10b981;
--color-warning: #f59e0b;
--color-error: #ef4444;
}
@media (prefers-color-scheme: dark) {
:root {
--color-background: #0f172a;
--color-background-soft: #1e293b;
--color-background-mute: #334155;
--color-border: #475569;
--color-border-hover: #64748b;
--color-heading: #f1f5f9;
--color-text: #cbd5e1;
--color-text-soft: #94a3b8;
--color-primary: #60a5fa;
--color-primary-hover: #3b82f6;
--color-primary-soft: #1e3a8a;
--color-secondary: #818cf8;
--color-success: #34d399;
--color-warning: #fbbf24;
--color-error: #f87171;
}
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
min-height: 100vh;
color: var(--color-text);
background: var(--color-background);
transition: color 0.5s, background-color 0.5s;
line-height: 1.6;
font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
color: var(--color-primary);
text-decoration: none;
transition: color 0.2s;
}
a:hover {
color: var(--color-primary-hover);
text-decoration: underline;
}
button {
cursor: pointer;
transition: all 0.2s;
}
button:disabled {
cursor: not-allowed;
opacity: 0.6;
}
src/App.tsx
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Header from './components/Header';
import Home from './pages/Home';
import About from './pages/About';
import Contact from './pages/Contact';
import NotFound from './pages/NotFound';
import './index.css';
const App: React.FC = () => {
return (
<Router>
<div className="min-h-screen bg-background">
<Header />
<main className="container mx-auto px-4 py-8">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
<Route path="*" element={<NotFound />} />
</Routes>
</main>
</div>
</Router>
);
};
export default App;
src/components/Header.tsx
import React, { useState } from 'react';
import { Link, useLocation } from 'react-router-dom';
const Header: React.FC = () => {
const [isMenuOpen, setIsMenuOpen] = useState(false);
const location = useLocation();
const toggleMenu = () => {
setIsMenuOpen(!isMenuOpen);
};
const isActive = (path: string) => location.pathname === path;
return (
<header className="bg-background-soft border-b border-border">
<nav className="container mx-auto px-4 py-4">
<div className="flex items-center justify-between">
<Link
to="/"
className="text-2xl font-bold text-heading hover:text-primary transition-colors"
>
React App
</Link>
<div className="hidden md:flex items-center space-x-6">
<Link
to="/"
className={`text-text hover:text-primary transition-colors ${
isActive('/') ? 'text-primary font-semibold' : ''
}`}
>
Home
</Link>
<Link
to="/about"
className={`text-text hover:text-primary transition-colors ${
isActive('/about') ? 'text-primary font-semibold' : ''
}`}
>
About
</Link>
<Link
to="/contact"
className={`text-text hover:text-primary transition-colors ${
isActive('/contact') ? 'text-primary font-semibold' : ''
}`}
>
Contact
</Link>
</div>
<button
onClick={toggleMenu}
className="md:hidden p-2 rounded-lg hover:bg-background-mute transition-colors"
aria-label="Toggle menu"
>
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
</button>
</div>
{isMenuOpen && (
<div className="md:hidden mt-4 pb-4 border-t border-border pt-4">
<Link
to="/"
className="block py-2 text-text hover:text-primary transition-colors"
onClick={() => setIsMenuOpen(false)}
>
Home
</Link>
<Link
to="/about"
className="block py-2 text-text hover:text-primary transition-colors"
onClick={() => setIsMenuOpen(false)}
>
About
</Link>
<Link
to="/contact"
className="block py-2 text-text hover:text-primary transition-colors"
onClick={() => setIsMenuOpen(false)}
>
Contact
</Link>
</div>
)}
</nav>
</header>
);
};
export default Header;
src/pages/Home.tsx
import React, { useState, useEffect } from 'react';
import Counter from '../components/Counter';
import WelcomeHero from '../components/WelcomeHero';
const Home: React.FC = () => {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
return <div className="text-center py-8">Loading...</div>;
}
return (
<div className="max-w-4xl mx-auto">
<WelcomeHero />
<div className="mt-12 p-8 bg-background-soft rounded-xl border border-border">
<h2 className="text-2xl font-bold text-heading mb-4 text-center">
Interactive Counter
</h2>
<p className="text-text-soft mb-6 text-center">
Click the buttons to increment or decrement the counter and test React's state management.
</p>
<Counter />
</div>
<div className="mt-8 grid md:grid-cols-2 gap-6">
<div className="p-6 bg-primary-soft rounded-lg border border-primary/20">
<h3 className="text-xl font-semibold text-heading mb-3">ā” Fast Development</h3>
<p className="text-text">
Built with Vite for lightning-fast development experience with instant HMR.
</p>
</div>
<div className="p-6 bg-background-soft rounded-lg border border-border">
<h3 className="text-xl font-semibold text-heading mb-3">šØ Modern Styling</h3>
<p className="text-text">
Styled with Tailwind CSS for rapid UI development and consistent design.
</p>
</div>
</div>
</div>
);
};
export default Home;
src/pages/About.tsx
import React from 'react';
const About: React.FC = () => {
return (
<div className="max-w-2xl mx-auto">
<h1 className="text-4xl font-bold text-heading mb-6 text-center">
About This App
</h1>
<div className="prose prose-slate dark:prose-invert mx-auto">
<p className="text-lg text-text leading-relaxed mb-6">
This is a modern React application built with TypeScript, React Router, and Tailwind CSS.
It demonstrates best practices for React development in 2025.
</p>
<div className="bg-background-soft rounded-lg p-6 border border-border mb-6">
<h2 className="text-2xl font-semibold text-heading mb-4">Features</h2>
<ul className="list-disc list-inside space-y-2 text-text">
<li>React 18 with modern hooks</li>
<li>TypeScript for type safety</li>
<li>React Router for navigation</li>
<li>Vite for fast development</li>
<li>Tailwind CSS for styling</li>
<li>ESLint & Prettier for code quality</li>
<li>Responsive design</li>
<li>Dark mode support</li>
</ul>
</div>
<div className="bg-primary-soft rounded-lg p-6 border border-primary/20">
<h3 className="text-xl font-semibold text-heading mb-3">Tech Stack</h3>
<div className="grid grid-cols-2 gap-4 text-sm">
<div>
<strong className="text-heading">Frontend:</strong>
<p className="text-text">React 18, TypeScript, Tailwind CSS</p>
</div>
<div>
<strong className="text-heading">Build Tool:</strong>
<p className="text-text">Vite with HMR</p>
</div>
<div>
<strong className="text-heading">Router:</strong>
<p className="text-text">React Router v6</p>
</div>
<div>
<strong className="text-heading">Linting:</strong>
<p className="text-text">ESLint, Prettier</p>
</div>
</div>
</div>
</div>
</div>
);
};
export default About;
src/pages/Contact.tsx
import React, { useState } from 'react';
interface FormData {
name: string;
email: string;
message: string;
}
const Contact: React.FC = () => {
const [formData, setFormData] = useState<FormData>({
name: '',
email: '',
message: ''
});
const [isSubmitted, setIsSubmitted] = useState(false);
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
console.log('Form submitted:', formData);
setIsSubmitted(true);
// Reset form after 3 seconds
setTimeout(() => {
setIsSubmitted(false);
setFormData({ name: '', email: '', message: '' });
}, 3000);
};
if (isSubmitted) {
return (
<div className="max-w-md mx-auto text-center">
<div className="bg-success/10 border border-success/20 rounded-lg p-6">
<div className="text-success text-4xl mb-4">ā</div>
<h2 className="text-xl font-semibold text-heading mb-2">Thank You!</h2>
<p className="text-text">Your message has been sent successfully.</p>
</div>
</div>
);
}
return (
<div className="max-w-md mx-auto">
<h1 className="text-3xl font-bold text-heading mb-6 text-center">
Contact Us
</h1>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="name" className="block text-sm font-medium text-heading mb-1">
Name
</label>
<input
type="text"
id="name"
name="name"
value={formData.name}
onChange={handleChange}
required
className="w-full px-3 py-2 border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent bg-background text-text"
placeholder="Your name"
/>
</div>
<div>
<label htmlFor="email" className="block text-sm font-medium text-heading mb-1">
Email
</label>
<input
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleChange}
required
className="w-full px-3 py-2 border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent bg-background text-text"
placeholder="your.email@example.com"
/>
</div>
<div>
<label htmlFor="message" className="block text-sm font-medium text-heading mb-1">
Message
</label>
<textarea
id="message"
name="message"
value={formData.message}
onChange={handleChange}
required
rows={4}
className="w-full px-3 py-2 border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent bg-background text-text resize-vertical"
placeholder="Your message..."
/>
</div>
<button
type="submit"
className="w-full bg-primary hover:bg-primary-hover text-white font-semibold py-2 px-4 rounded-lg transition-colors"
>
Send Message
</button>
</form>
</div>
);
};
export default Contact;
src/pages/NotFound.tsx
import React from 'react';
import { Link } from 'react-router-dom';
const NotFound: React.FC = () => {
return (
<div className="text-center max-w-md mx-auto">
<div className="text-6xl font-bold text-primary mb-4">404</div>
<h1 className="text-2xl font-bold text-heading mb-4">Page Not Found</h1>
<p className="text-text-soft mb-6">
The page you're looking for doesn't exist or has been moved.
</p>
<Link
to="/"
className="inline-block bg-primary hover:bg-primary-hover text-white font-semibold py-2 px-6 rounded-lg transition-colors"
>
Go Home
</Link>
</div>
);
};
export default NotFound;
src/components/WelcomeHero.tsx
import React from 'react';
interface WelcomeHeroProps {
title?: string;
subtitle?: string;
}
const WelcomeHero: React.FC<WelcomeHeroProps> = ({
title = 'Welcome to React',
subtitle = 'A modern, fast, and scalable web application built with React 18, TypeScript, and Vite. Experience the power of modern React development.'
}) => {
return (
<div className="text-center mb-12">
<h1 className="text-5xl font-bold text-heading mb-4">
{title}
</h1>
<p className="text-xl text-text-soft max-w-2xl mx-auto leading-relaxed mb-8">
{subtitle}
</p>
<div className="flex gap-4 justify-center">
<a
href="https://react.dev/"
target="_blank"
rel="noopener noreferrer"
className="bg-primary hover:bg-primary-hover text-white px-6 py-3 rounded-lg transition-colors font-semibold"
>
Learn React
</a>
<a
href="https://vitejs.dev/"
target="_blank"
rel="noopener noreferrer"
className="border border-border hover:border-border-hover px-6 py-3 rounded-lg transition-colors font-semibold text-text hover:text-heading"
>
Powered by Vite
</a>
</div>
</div>
);
};
export default WelcomeHero;
src/components/Counter.tsx
import React, { useState, useCallback } from 'react';
const Counter: React.FC = () => {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount(prev => prev + 1);
}, []);
const decrement = useCallback(() => {
setCount(prev => prev - 1);
}, []);
const reset = useCallback(() => {
setCount(0);
}, []);
return (
<div className="text-center">
<div className="flex items-center justify-center gap-4 mb-6">
<button
onClick={decrement}
className="bg-error hover:bg-error/90 text-white px-4 py-2 rounded-lg transition-colors font-semibold min-w-[40px]"
>
-
</button>
<div className="bg-background border border-border px-6 py-2 rounded-lg min-w-[80px]">
<span className="text-2xl font-mono text-heading">{count}</span>
</div>
<button
onClick={increment}
className="bg-success hover:bg-success/90 text-white px-4 py-2 rounded-lg transition-colors font-semibold min-w-[40px]"
>
+
</button>
</div>
<div className="flex gap-2 justify-center">
<button
onClick={reset}
className="bg-background-mute hover:bg-border text-text px-4 py-2 rounded-lg transition-colors text-sm"
>
Reset
</button>
</div>
<p className="text-sm text-text-soft mt-4">
Current count: <span className="font-mono text-primary">{count}</span>
</p>
</div>
);
};
export default Counter;
src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
package.json
{
"name": "react-app",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"lint": "eslint . --ext .ts,.tsx --report-unused-disable-directives --max-warnings 0",
"lint:fix": "eslint . --ext .ts,.tsx --fix",
"type-check": "tsc --noEmit",
"format": "prettier --write src/"
},
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.28.0"
},
"devDependencies": {
"@types/react": "^18.3.17",
"@types/react-dom": "^18.3.5",
"@typescript-eslint/eslint-plugin": "^8.18.1",
"@typescript-eslint/parser": "^8.18.1",
"@vitejs/plugin-react": "^4.3.4",
"autoprefixer": "^10.4.20",
"eslint": "^8.57.1",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.16",
"postcss": "^8.5.1",
"prettier": "^3.4.2",
"tailwindcss": "^3.4.17",
"typescript": "^5.7.2",
"vite": "^6.0.3"
}
}
tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
tsconfig.node.json
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"strict": true,
"types": ["node"]
},
"include": ["vite.config.ts"]
}
vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { resolve } from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
},
},
server: {
port: 3000,
open: true,
},
build: {
outDir: 'dist',
sourcemap: true,
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
router: ['react-router-dom'],
},
},
},
},
})
tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
colors: {
'background': 'var(--color-background)',
'background-soft': 'var(--color-background-soft)',
'background-mute': 'var(--color-background-mute)',
'border': 'var(--color-border)',
'border-hover': 'var(--color-border-hover)',
'heading': 'var(--color-heading)',
'text': 'var(--color-text)',
'text-soft': 'var(--color-text-soft)',
'primary': {
DEFAULT: 'var(--color-primary)',
hover: 'var(--color-primary-hover)',
soft: 'var(--color-primary-soft)',
},
'secondary': 'var(--color-secondary)',
'success': 'var(--color-success)',
'warning': 'var(--color-warning)',
'error': 'var(--color-error)',
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
}
},
},
plugins: [],
}
postcss.config.js
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
eslint.config.js
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from '@typescript-eslint/eslint-plugin'
import tsParser from '@typescript-eslint/parser'
export default [
{
ignores: ['dist'],
},
{
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parser: tsParser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
'@typescript-eslint': tseslint,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
'@typescript-eslint/no-unused-vars': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
},
},
]
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>React App</title>
<meta name="description" content="A modern React application with TypeScript and Tailwind CSS" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
README.md
# React Modern Template
A modern React 18 application built with TypeScript, React Router, and Tailwind CSS.
## Features
- ā” **React 18** - Latest version with concurrent features
- š **Vite** - Lightning fast build tool with HMR
- š **TypeScript** - Full TypeScript support with strict mode
- š£ļø **React Router** - Declarative routing for React applications
- šØ **Tailwind CSS** - Utility-first CSS framework
- š **Dark Mode** - Built-in dark mode support
- š± **Responsive** - Mobile-first responsive design
- šÆ **ESLint & Prettier** - Code linting and formatting
- š§ **Path Aliases** - Clean imports with @ alias
- šļø **Component Structure** - Well-organized component architecture
## Getting Started
Install dependencies:
```bash
# npm
npm install
# pnpm
pnpm install
# yarn
yarn install
# bun
bun install
```
## Development
Run the development server:
```bash
# npm
npm run dev
# pnpm
pnpm run dev
# yarn
yarn dev
# bun
bun run dev
```
The application will open at [http://localhost:3000](http://localhost:3000).
## Production
Build for production:
```bash
# npm
npm run build
# pnpm
pnpm run build
# yarn
yarn build
# bun
bun run build
```
Preview production build:
```bash
# npm
npm run preview
# pnpm
pnpm run preview
# yarn
yarn preview
# bun
bun run preview
```
## Development Tools
Type checking:
```bash
npm run type-check
```
Lint and fix code:
```bash
npm run lint
npm run lint:fix
```
Format code:
```bash
npm run format
```
## Project Structure
```
āāā public/ # Static assets
āāā src/
ā āāā components/ # Reusable React components
ā āāā pages/ # Page components
ā āāā App.tsx # Root component
ā āāā main.tsx # Application entry point
ā āāā index.css # Global styles
āāā index.html # HTML template
āāā vite.config.ts # Vite configuration
āāā tailwind.config.js # Tailwind configuration
āāā tsconfig.json # TypeScript configuration
```
## Key Technologies
- **React 18**: Modern reactive library with hooks and concurrent features
- **TypeScript**: Type-safe JavaScript with excellent IDE support
- **Vite**: Next-generation frontend build tool
- **React Router**: Official routing solution for React applications
- **Tailwind CSS**: Utility-first CSS framework
- **ESLint**: Code linting and error detection
- **Prettier**: Code formatting and style consistency
## Component Features
- **Functional Components**: Modern React with hooks
- **TypeScript Props**: Type-safe component props with interfaces
- **State Management**: React's built-in state with useState and useEffect
- **Navigation**: React Router with active link highlighting
- **Form Handling**: Controlled components with validation
- **Responsive Design**: Mobile-first approach with Tailwind
- **Dark Mode**: CSS custom properties with system preference detection
## Best Practices
- **Component Organization**: Clear separation of concerns
- **Type Safety**: Comprehensive TypeScript usage
- **Performance**: React.memo and useCallback for optimization
- **Accessibility**: Semantic HTML and ARIA attributes
- **Code Quality**: ESLint rules and Prettier formatting
- **Modern React**: Hooks-based architecture
- **Clean Code**: Self-documenting code with meaningful names
## Learn More
- [React Documentation](https://react.dev/)
- [React Router Documentation](https://reactrouter.com/)
- [Vite Documentation](https://vitejs.dev/)
- [Tailwind CSS Documentation](https://tailwindcss.com/)
- [TypeScript Documentation](https://www.typescriptlang.org/)
Nuxt
Vue
Want to update?
Subscribe to my blog to receive the latest updates from us.
Monthly articles
New articles will be created every month. No spam
All notifications are notified to you, not spam or advertising.