A modern and efficient React starter template with TypeScript, Tailwind CSS, and various development tools pre-configured.
- β‘οΈ React 19.2.3 with TypeScript 5.9.3
- βοΈ React Compiler enabled via Babel plugin for automatic optimization
- π¨ Tailwind CSS v4 for styling
- π¦ Vite 7.2.7 for fast development and building
- π ESLint for code linting
- π Prettier for code formatting
- πΆ Husky for Git hooks
- π Commitlint for conventional commits
- πͺ Zustand for state management
- π React Router 7 for routing
- π Day.js for date manipulation
- π Axios for HTTP requests
- π Nuqs for URL query state management
- β‘ Custom
use-fetchanduse-mutationhooks for data fetching - π i18next for internationalization
- Node.js (v18 or higher)
- Bun (latest version)
npx turbo-setup react-tailwindClone the repository:
git clone https://github.com/khoivudevz/turbo-setup-react-ts-tailwind
cd turbo-setup-react-ts-tailwindInstall dependencies:
bun install# Start development server (http://localhost:8000)
bun run dev
# Build for production
bun run build
# Preview production build
bun run preview
# Run linting
bun run lint- Vite 7.2.7: Lightning-fast HMR and builds
- React 19.2.3: Latest React with new features
- React Compiler: Automatic optimization via Babel plugin
- Hot Module Replacement: Instant updates during development
- TypeScript: Full type checking and IntelliSense
- ESLint: Code quality and consistency
- Prettier: Automatic code formatting
- Husky: Git hooks for quality assurance
src/
βββ assets/ # Static assets (images, fonts, icons)
βββ components/ # Reusable UI components (snake_case naming)
β βββ auth-demo/
β β βββ auth-demo.tsx
β βββ button/
β β βββ button.tsx
β βββ modal/
β β βββ components/
β β β βββ demo-modal.tsx
β β βββ modal.tsx
β βββ mutation-demo/
β β βββ mutation-demo.tsx
β βββ search-demo/
β β βββ search-demo.tsx
β β βββ search-result.tsx
β βββ switch-language/
β βββ switch-language.tsx
βββ configs/ # Configuration files (env, http, app urls)
β βββ app-url.config.ts
β βββ env.config.ts
β βββ http.config.ts
βββ constants/ # Application constants and shared values
β βββ common.constant.ts
β βββ modals.constant.ts
βββ hooks/ # Custom React hooks organized by feature
β βββ auth/ # Authentication hooks
β β βββ use-auth.ts
β β βββ use-login.ts
β βββ common/ # Common/shared hooks
β β βββ use-clear-modals.ts
β β βββ use-fetch.ts
β β βββ use-key-press.ts
β β βββ use-mutation.ts
β βββ news/ # News feature hooks
β β βββ use-news.ts
β βββ user/ # User management hooks
β βββ use-create-user.ts
β βββ use-delete-user.ts
β βββ use-update-user.ts
βββ i18n/ # Internationalization
β βββ i18n.ts
β βββ translations/
β βββ en.json
β βββ ko.json
βββ layouts/ # Layout components and templates
β βββ main-layout.tsx
βββ pages/ # Page components (routing entry points)
β βββ example-page.tsx
βββ providers/ # React context providers
β βββ app-provider.tsx
βββ router/ # Routing configuration
β βββ lazy-components.tsx
β βββ router.tsx
βββ services/ # Browser services (cookies, localStorage)
β βββ cookie.service.ts
β βββ dumb.service.ts
β βββ localStorage.service.ts
βββ store/ # State management with Zustand
β βββ use-count.store.ts
β βββ use-modal.store.ts
β βββ use-user.store.ts
βββ styles/ # Global styles and Tailwind imports
β βββ index.css
βββ types/ # TypeScript type definitions
β βββ auth.type.ts
β βββ common.type.ts
βββ utils/ # Utility functions (snake_case naming)
β βββ cn.ts
β βββ delay.ts
β βββ format-date.ts
β βββ text-slice-with-dot.ts
βββ views/ # View components (pure presentation)
βββ example-view/
βββ example-view.tsx
This project follows a snake_case naming convention with feature-based organization:
- Files: Use snake_case (e.g.,
use-auth.ts,modal-wrapper.tsx) - Directories: Use snake_case (e.g.,
example-view/,search-demo/) - Components: Use PascalCase in code, snake_case for filenames
- Hooks: Organized by feature with
use-prefix (e.g.,hooks/auth/use-login.ts) - Stores: Use snake_case with
.store.tssuffix (e.g.,use-modal.store.ts)
β
Correct:
- src/hooks/auth/use-auth.ts
- src/hooks/common/use-fetch.ts
- src/hooks/user/use-create-user.ts
- src/views/example-view/example-view.tsx
- src/store/use-modal.store.ts
- src/utils/format-date.ts
β Avoid:
- src/hooks/useAuth.ts
- src/views/HomeView/HomeView.tsx
- Scalability: Easy to add new features without cluttering the structure
- Consistency: Uniform naming across all files
- Readability: Easier to scan and understand file structure
- Maintainability: Clear patterns for different file types
This project uses a clear separation between Pages and Views to maintain clean architecture:
Pages (src/pages/):
- Routing entry points - Directly referenced by the router
- Data fetching layer - Handle API calls, route parameters, authentication
- Layout orchestration - Decide which layout to use
- Error handling - Loading states, error boundaries
- Minimal UI - Just composition and data preparation
Views (src/views/):
- Pure presentation components - Focused on UI rendering
- Reusable across different pages - Same view can be used in different contexts
- Business logic - Form handling, user interactions, component composition
- Props-based - Receive data from pages as props
// src/pages/home-page/home-page.tsx
const HomePage = () => {
// Data fetching, route params, auth checks
const { data, loading, error } = useHomeData()
if (loading) return <LoadingSpinner />
if (error) return <ErrorPage />
return <HomeView data={data} />
}
// src/views/home-view/home-view.tsx
interface HomeViewProps {
data: HomeData
}
const HomeView = ({ data }: HomeViewProps) => {
// Pure presentation logic
// All UI components and interactions
}- Testability - Views can be tested independently with mock data
- Reusability - Same view can be used across different pages
- Clear responsibilities - Pages handle data, Views handle presentation
- Easier maintenance - Changes to data fetching don't affect UI logic
- Better code organization - Clear separation of concerns
Create .env files for different environments:
VITE_ENV=development
VITE_API_URL=your_api_url
The project includes two TypeScript configurations:
tsconfig.app.json- Application configurationtsconfig.node.json- Node.js configuration
- ESLint is configured with TypeScript and React rules
- Prettier is set up with custom formatting rules
- Pre-commit hooks ensure code quality
The project uses React Compiler via babel-plugin-react-compiler for automatic optimization of React components. The compiler is configured in vite.config.ts using @vitejs/plugin-react (Babel-based) to support Babel plugins.
Note: The project uses @vitejs/plugin-react instead of @vitejs/plugin-react-swc to enable Babel plugin support for the React Compiler.
This project uses i18next with react-i18next for internationalization support. The translations are stored in JSON files located in the src/i18n/translations directory.
-
Create a new JSON file in the
src/i18n/translationsdirectory with the language code as the filename (e.g.,fr.jsonfor French). -
Add your translations in the new JSON file. For example:
{ "translation": { "welcome": "Bienvenue Γ React, tailwindcss et plus" } }
The SwitchLanguage component allows users to switch between available languages. It uses the useTranslation hook from react-i18next to change the language dynamically.
Example usage in a component:
import {useTranslation} from 'react-i18next'
import SwitchLanguage from '@/components/SwitchLanguage/SwitchLanguage'
const HomeView = () => {
const {t} = useTranslation()
return (
<div>
<p>{t('welcome')}</p>
<SwitchLanguage />
</div>
)
}The project uses nuqs for managing URL query state:
import {useQueryState} from 'nuqs'
const SearchDemo = () => {
const [name, setName] = useQueryState('name')
return (
<input
value={name || ''}
onChange={(e) => setName(e.target.value)}
placeholder="Search..."
/>
)
}- URL Synchronization: State is automatically synced with URL query parameters
- Shareable URLs: Users can share URLs with specific state
- Browser History: Navigation works with browser back/forward buttons
- Type-Safe: Full TypeScript support
This project uses a custom use-fetch hook for data fetching, which provides:
- Simple and lightweight data fetching
- Loading state management
- Error handling
- TypeScript support
- Conditional fetching with
enabledoption - Manual execution control
The project includes custom hooks for data fetching:
A flexible hook for data fetching with conditional support:
import useFetch from '@/hooks/common/use-fetch'
// Basic usage
const {data, isLoading, error, execute, reset} = useFetch(() => api.getData(), {
immediate: true,
})
// Conditional fetching
const {data, isLoading, error} = useFetch(() => api.getData(), {
immediate: true,
enabled: shouldFetch, // Only fetch when condition is true
})
// Manual fetching
const {data, isLoading, error, execute} = useFetch(
() => api.getData(),
{immediate: false} // Don't fetch automatically
)
// Then call execute() manually when neededA powerful hook for handling mutations (POST, PUT, DELETE operations):
import useMutation from '@/hooks/common/use-mutation'
// Basic usage
const {data, isLoading, isError, isSuccess, error, mutate, reset} = useMutation({
onSuccess: (data) => {
console.log('User created:', data)
},
onError: (error) => {
console.error('Failed to create user:', error)
},
})
// Usage in component
const MyComponent = () => {
const createUser = useMutation()
const handleSubmit = async (formData) => {
await createUser.mutate(async (userData) => {
const response = await api.post('/users', userData)
return response
}, formData)
}
return (
<form onSubmit={handleSubmit}>
<button disabled={createUser.isLoading}>
{createUser.isLoading ? 'Creating...' : 'Create User'}
</button>
{createUser.isSuccess && <div>User created successfully!</div>}
{createUser.isError && <div>Error: {createUser.error.message}</div>}
</form>
)
}The project includes specialized hooks for common operations:
useCreateUser Hook:
import useCreateUser from '@/hooks/user/use-create-user'
const MyComponent = () => {
const {createUser, data, isLoading, isError, isSuccess, error, reset} = useCreateUser()
const handleSubmit = async (formData) => {
await createUser({
name: formData.name,
email: formData.email,
role: 'user'
})
}
return (
<form onSubmit={handleSubmit}>
<button disabled={isLoading}>
{isLoading ? 'Creating...' : 'Create User'}
</button>
{isSuccess && <div>User created: {data?.name}</div>}
{isError && <div>Error: {error?.message}</div>}
</form>
)
}useUpdateUser Hook:
import useUpdateUser from '@/hooks/user/use-update-user'
const MyComponent = () => {
const {updateUser, isLoading, isSuccess, error} = useUpdateUser()
const handleUpdate = async (userData) => {
await updateUser({
id: 'user-123',
name: userData.name,
email: userData.email,
})
}
}useDeleteUser Hook:
import useDeleteUser from '@/hooks/user/use-delete-user'
const MyComponent = () => {
const {deleteUser, isLoading, isSuccess, error} = useDeleteUser()
const handleDelete = async (userId) => {
await deleteUser({id: userId})
}
}useLogin Hook:
import useLogin from '@/hooks/auth/use-login'
const MyComponent = () => {
const {login, data, isLoading, isSuccess, error} = useLogin()
const handleLogin = async (credentials) => {
await login({
email: credentials.email,
password: credentials.password,
})
}
}A custom hook for fetching news data:
import useNews from '@/hooks/news/use-news'
const MyComponent = () => {
const { news, isLoading, error, refetch } = useNews()
if (isLoading) return <div>Loading...</div>
if (error) return <div>Error loading news</div>
return (
<div>
{news?.map(item => (
<div key={item.ticker}>{item.name}</div>
))}
<button onClick={refetch}>Refresh News</button>
</div>
)
}- Automatic fetching: Set
immediate: trueto fetch on mount - Conditional fetching: Use
enabledoption to control when to fetch - Manual control: Call
execute()to fetch manually - Error handling: Built-in error state management
- Loading states: Automatic loading state management
- Reset functionality: Call
reset()to clear data and error states - TypeScript support: Full type safety with generics
- Loading states:
isLoadingfor pending operations - Success states:
isSuccessanddatafor successful operations - Error states:
isErroranderrorfor failed operations - Flexible execution: Call
mutate(mutationFn, variables)with any async function - Callbacks:
onSuccess,onError, andonSettledfor side effects - Reset functionality: Call
reset()to clear all states - TypeScript support: Full type safety with generics
- Promise handling: Both sync (
mutate) and async (mutateAsync) execution - Dynamic mutations: Pass different mutation functions on each call
The project includes a comprehensive demo component (src/components/mutation-demo/mutation-demo.tsx) that showcases all mutation patterns:
- Create User Form: Complete form with validation and success/error states
- Update User: Button-based update with loading states
- Delete User: Confirmation-style deletion with feedback
- Login Form: Authentication form with token handling
- Reset All: Clear all mutation states
import MutationDemo from '@/components/mutation-demo/mutation-demo'
const App = () => {
return <MutationDemo />
}The demo component demonstrates:
- Real-world form handling
- Loading state management
- Error handling and display
- Success feedback
- State reset functionality
- TypeScript integration
| Technology | Version | Description |
|---|---|---|
| React | 19.2.3 | UI library with compiler optimizations |
| TypeScript | 5.9.3 | Type-safe JavaScript |
| Vite | 7.2.7 | Next-generation build tool |
| TailwindCSS | 4.1.18 | Utility-first CSS framework |
| React Router | 7.10.1 | Declarative routing |
| Zustand | 5.0.9 | Lightweight state management |
| i18next | 25.7.2 | Internationalization framework |
| react-i18next | 16.5.0 | React bindings for i18next |
| nuqs | 2.8.5 | URL query state management |
| Axios | 1.13.2 | HTTP client |
| Day.js | 1.11.19 | Date manipulation |
| styled-components | 6.1.19 | CSS-in-JS |
| Husky | 9.1.7 | Git hooks |
| ESLint | 9.39.2 | Code linting |
| Prettier | 3.7.4 | Code formatting |
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes using conventional commits
- Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License.