A modern React starter template featuring file-based routing with TanStack Router, a custom type-safe internationalization system, and a feature-based architecture β ready for production.
This template gives you a fully configured React application without any boilerplate decisions to make. It combines the best of file-based routing (automatic route generation) with the flexibility of code-based routing (custom URL paths via configuration), all in TypeScript.
What makes this template different:
- Routes are generated automatically from your file structure β just create a
.tsxfile and it becomes a route - A custom i18n system with full TypeScript autocomplete β no external dependencies, no runtime overhead
- Rolldown-powered Vite for near-instant builds and HMR
- React 19 with React Compiler for automatic memoization
- Automatic route generation from
src/routes/directory structure - Three route groups:
public/(basePath/),auth/(basePath/auth),protected/(basePath/app) - Custom URL paths via
route.config.tswithout changing file structure - Layout wrappers via
_layout.tsxfiles (e.g. authentication guards) - Dynamic route parameters with
$param.tsxnaming - Hot reload β the watcher regenerates routes on file add/delete
- Zero external dependencies β pure TypeScript implementation
- Auto-generated types from your translation files β full IDE autocomplete for
t("key") - Multi-language support (French and English included, easily extensible)
- CLI parser scans your codebase and syncs translation keys automatically
- Vite with Rolldown β ultra-fast builds and HMR
- React 19 with React Compiler (automatic memoization)
- TailwindCSS 4 β utility-first styling with latest engine
- TypeScript strict mode β catch errors at compile time
- ESLint + Prettier β consistent code style enforced
- Path aliases β
@/maps tosrc/for clean imports
# Clone the repository
git clone https://github.com/MarleyApong/reactjs-tailwindcss-template.git my-app
cd my-app
# Install dependencies
npm install
# Start the development server (Vite + route watcher in parallel)
npm run devThe dev server starts at http://localhost:5179.
reactjs-tailwindcss-template/
βββ docs/ # Documentation
β βββ watch-routes.md # Route watcher documentation
β βββ route.config.md # route.config.ts documentation
β βββ router.md # router.ts documentation
β
βββ scripts/
β βββ watch-routes.ts # Route watcher (generates _root.tsx + router.ts)
β βββ i18n/
β βββ i18n-parser.js # Translation key scanner
β
βββ src/
β βββ features/ # Domain-specific features
β β βββ docs/ # Built-in documentation feature
β β βββ components/
β β βββ index.ts # Public API export
β β
β βββ routes/ # File-based routes
β β βββ root.tsx # Root route (manual, do not delete)
β β βββ route.config.ts # URL path configuration (auto-synced)
β β βββ public/ # Public routes β basePath "/"
β β β βββ _root.tsx # Auto-generated (do not edit)
β β β βββ home.tsx # β URL: /
β β β βββ docs.tsx # β URL: /docs
β β βββ auth/ # Auth routes β basePath "/auth"
β β β βββ _root.tsx # Auto-generated (do not edit)
β β β βββ login.tsx # β URL: /auth/login
β β β βββ register.tsx # β URL: /auth/register
β β β βββ hello.tsx # β URL: /auth/hello
β β βββ protected/ # Protected routes β basePath "/app"
β β βββ _root.tsx # Auto-generated (do not edit)
β β βββ dashboard.tsx # β URL: /app/dashboard
β β βββ me.tsx # β URL: /app/me
β β βββ profile.tsx # β URL: /app/profile
β β βββ settings.tsx # β URL: /app/settings
β β
β βββ shared/ # Reusable resources
β β βββ i18n/ # Internationalization system
β β βββ locales/
β β β βββ fr.ts # French translations
β β β βββ en.ts # English translations
β β β βββ index.ts # Language configuration
β β βββ index.tsx # I18nProvider + useTranslation hook
β β βββ types.ts # Auto-generated translation types
β β
β βββ router.ts # Auto-generated route tree (do not edit)
β βββ App.tsx # Root component
β βββ main.tsx # Application entry point
β
βββ package.json
βββ vite.config.ts
βββ tsconfig.json
βββ tailwind.config.cjs
| Command | Description |
|---|---|
npm run dev |
Start Vite dev server + route watcher in parallel |
npm run dev:vite |
Start only the Vite dev server |
npm run watch:routes |
Start only the route watcher |
| Command | Description |
|---|---|
npm run build |
Production build with TypeScript type checking |
npm run preview |
Preview the production build locally |
| Command | Description |
|---|---|
npm run lint |
Run ESLint on the codebase |
npm run format |
Format code with Prettier |
npm run format:check |
Check formatting without making changes |
| Command | Description |
|---|---|
npm run parse |
Basic translation key scan |
npm run parse:verbose |
Scan with detailed output |
npm run parse:sort |
Scan and sort keys alphabetically |
npm run parse:clean |
Scan and remove unused keys |
npm run parse:all |
All options combined (recommended) |
| Command | Description |
|---|---|
npm run release:dev |
Create a development prerelease |
npm run release:prod |
Create a production release |
The route watcher (scripts/watch-routes.ts) monitors src/routes/ and automatically:
- Scans all
.tsxfiles in route group directories - Syncs
route.config.ts(adds new routes, removes deleted ones) - Regenerates
_root.tsxfiles for each route group - Regenerates
src/router.tswith the full route tree
Files you edit: home.tsx, login.tsx, dashboard.tsx, etc.
Files auto-generated (do not edit): _root.tsx files, src/router.ts
| Group | Base Path | Example Files | Example URLs |
|---|---|---|---|
public/ |
/ |
home.tsx, about.tsx |
/, /about |
auth/ |
/auth |
login.tsx, register.tsx |
/auth/login, /auth/register |
protected/ |
/app |
dashboard.tsx, settings.tsx |
/app/dashboard, /app/settings |
Edit src/routes/route.config.ts to customize URL paths:
export const routeConfig = {
// Make home the site root
"public/home": { path: "/", override: true },
// Keep default path structure
"auth/login": { path: "login", override: false }, // β /auth/login
// Override to absolute path
"auth/register": { path: "/register", override: true }, // β /register
}After editing
route.config.ts, restart the dev server (Ctrl+C thennpm run dev).
-
Create a file in the appropriate route group:
// src/routes/public/about.tsx export default function About() { return ( <div className="container mx-auto px-4 py-8"> <h1>About Us</h1> </div> ) }
-
The watcher automatically:
- Adds
"public/about"toroute.config.ts - Regenerates
public/_root.tsxwithpublicAboutRoute - Regenerates
src/router.ts
- Adds
-
The route is immediately accessible at
/about
Add a _layout.tsx file to a route group to wrap all its routes (e.g. authentication guard):
// src/routes/protected/_layout.tsx
import { Outlet, redirect } from '@tanstack/react-router'
export default function ProtectedLayout() {
const isAuthenticated = checkAuth()
if (!isAuthenticated) {
throw redirect({ to: '/auth/login' })
}
return <Outlet />
}The watcher detects _layout.tsx and sets it as the component for the group's parent route.
Create files with $ prefix for dynamic segments:
src/routes/protected/$userId.tsx β URL: /app/:userId
src/routes/protected/posts/$postId.tsx β URL: /app/posts/:postId
Access params in the component:
import { useParams } from '@tanstack/react-router'
export default function UserPage() {
const { userId } = useParams({ strict: false })
return <div>User: {userId}</div>
}import { useTranslation } from "@/shared/i18n/index.tsx"
export default function MyComponent() {
const { t, changeLanguage, currentLanguage } = useTranslation()
return (
<div>
<h1>{t("home.title")}</h1>
<button onClick={() => changeLanguage("en")}>English</button>
<button onClick={() => changeLanguage("fr")}>FranΓ§ais</button>
</div>
)
}- Use
t("your.key")in any component - Run
npm run parse:allto scan your code and add missing keys - Edit the translation files with actual values:
// src/shared/i18n/locales/en.ts export const en = { home: { title: "Welcome", }, }
- TypeScript types are updated automatically β IDE autocomplete works immediately
-
Create
src/shared/i18n/locales/es.ts:export const es = { home: { title: "Bienvenido", }, }
-
Add it to
src/shared/i18n/locales/index.ts:import { es } from './es' export const supportedLanguages = { fr: { name: 'FranΓ§ais', flag: 'π«π·', translations: fr }, en: { name: 'English', flag: 'πΊπΈ', translations: en }, es: { name: 'EspaΓ±ol', flag: 'πͺπΈ', translations: es }, }
-
Add
'es'tosupportedLanguagesinscripts/i18n/i18n-parser.js
The codebase uses a feature-based architecture:
src/features/
βββ my-feature/
βββ components/ # UI components for this feature
βββ hooks/ # Custom hooks
βββ types/ # TypeScript types
βββ services/ # API calls
βββ index.ts # Public API (only export what's needed)
Rules:
- Features must not import from other features
- Features may only import from
src/shared/ - Export public API through
index.ts
| Technology | Version | Purpose |
|---|---|---|
| React | 19 | UI library |
| TypeScript | 5.9 | Type safety |
| Vite | Latest (Rolldown) | Build tool & dev server |
| TanStack Router | 1.x | Type-safe routing |
| TailwindCSS | 4 | Utility-first CSS |
| ESLint | 9 | Code linting |
| Prettier | Latest | Code formatting |
| chokidar | 4 | File watching |
| File | Purpose |
|---|---|
vite.config.ts |
Vite + Rolldown + TailwindCSS + React Compiler |
tsconfig.json |
TypeScript strict configuration |
eslint.config.js |
ESLint with TypeScript rules |
.prettierrc |
Prettier formatting rules |
src/routes/route.config.ts |
Route URL path overrides |
src/shared/i18n/locales/ |
Translation files |
MIT