A comprehensive, production-ready and scalable Next.js 16 starter template with TypeScript, featuring a complete form system, state management, API clients, and dark mode support.
If you want to start with a clean slate, delete all documentation and examples:
npm run cleanupOr directly with bash:
bash scripts/cleanup.shThis script will:
- ❌ Delete
/docsdirectory - ❌ Delete
/examplesdirectory - ❌ Delete
/app/exampledirectory - ✏️ Reset
app/page.tsxto a minimal home page - ✏️ Reset
README.mdto a basic template
Per-directory/file confirmation: By default, you will be prompted before each directory or file is deleted (docs, examples, app/example, app/page.tsx, README.md). Confirm with 'y' to proceed or any other key to skip that item.
Force mode: To skip all prompts and force cleanup, use:
bash scripts/cleanup.sh --force
# or
bash scripts/cleanup.sh -fThis will delete all targeted files and directories without any confirmation.
Note: This action is tracked by Git, so you can undo with git checkout .
- Features
- Tech Stack
- Getting Started
- Project Structure
- Documentation
- Examples
- For Developers
- Contributing
- License
- ✅ Dark Mode Support - Seamless theme switching with
next-themes - ✅ Tailwind CSS v4 - Modern utility-first styling
- ✅ shadcn/ui Integration - Beautiful, accessible components
- ✅ Responsive Design - Mobile-first approach
- ✅ Theme Toggle Component - Multiple variants (slide & click-small)
- ✅ React Hook Form - Performant form validation
- ✅ 13 Pre-built Components - Input, Select, Upload, Checkbox, Radio, OTP, etc.
- ✅ Shadcn-style OTP - Individual character input boxes
- ✅ Auto-floating Labels - Smart label behavior
- ✅ Password Toggle - Built-in visibility control
- ✅ Theme Support - All components support light/dark themes
- ✅ useDialog Hook - Complete dialog state management (recommended)
- ✅ DialogCreator Component - Direct component usage for simple dialogs
- ✅ Per-Button Loading - Individual loading states for each button
- ✅ Async Handlers - Automatic loading during async operations
- ✅ Three Button Types - Cancel, Middle (optional), and Action buttons
- ✅ Button Variants - Multiple styles (default, destructive, outline, secondary, ghost)
- ✅ Ripple-enabled Action Buttons -
ActionButtonhelper andRippleButtonutility for card/dialog actions - ✅ Size Options - Small, Medium, Large, Extra Large dialogs
- ✅ Form Support - Built-in custom form integration
- ✅ TypeScript Support - Full type safety with complete interfaces
- ✅ Zustand - Lightweight state management
- ✅ React Query (TanStack) - Server state & caching
- ✅ Persistent Storage - Auto-save to localStorage
- ✅ Pre-configured Stores - Auth & UI stores ready to use
- ✅ Axios Clients - Separate internal & external API clients
- ✅ Request/Response Interceptors - Auto-error handling
- ✅ Cookie Support - Session management ready
- ✅ TypeScript Types - Full type safety
- ✅ Sortable Columns - Click-to-sort with visual indicators
- ✅ Pagination - Built-in pagination with customizable page sizes
- ✅ Row Selection - Single or multi-select with checkboxes
- ✅ Actions Column - Dropdown actions for each row
- ✅ Empty & Error States - Beautiful placeholder states
- ✅ Loading Skeleton - Smooth loading experience
- ✅ Dark Mode - Full theme support
- ✅ Custom Tooltips - Variant-based (info, success, warning, error)
- ✅ Multiple Sizes - Small, medium, large options
- ✅ Positioning - Top, bottom, left, right with alignment
- ✅ Toast Notifications - Sonner-powered with promise support
- ✅ Pre-configured Messages - Toast message constants
- ✅ ActionMenu Component - Easy-to-use action dropdowns
- ✅ Grouped Items - Organize actions with labels
- ✅ Checkbox & Radio - Selection menus
- ✅ Submenus - Nested dropdown support
- ✅ Keyboard Shortcuts - Display shortcut hints
- ✅ Destructive Actions - Visual warning for dangerous actions
- ✅ 13 Filter Types - Text, select, multi-select, number range, date range, checkbox, radio, search, tags, and more
- ✅ URL Synchronization - Filters sync with URL query params
- ✅ Two Display Modes - Tabs mode or compact dropdown mode
- ✅ TypeScript Support - Fully typed filter configurations
- ✅ Debounced Inputs - Optimized performance for text filters
- ✅ Theme Support - Works seamlessly with dark mode
- ✅ Middleware Chaining - Compose multiple middlewares in sequence
- ✅ Auth Guard - Built-in authentication middleware
- ✅ Skip Static Assets - Automatically bypass middleware for static files
- ✅ Type-Safe - Full TypeScript support with custom middleware types
- ✅ Easy to Extend - Simple pattern for creating custom middlewares
- ✅ Examples Included - Logging, rate limiting, security headers, and more
- ✅ TypeScript - Full type safety throughout
- ✅ Path Constants - Centralized route management
- ✅ Comprehensive Docs - Complete documentation for all features
- ✅ Example Routes - Organized examples at
/example/*
| Technology | Purpose | Version |
|---|---|---|
| Next.js | React framework | 16.0.3 |
| React | UI library | 19.2.0 |
| TypeScript | Type safety | 5.0 |
| Tailwind CSS | Styling | 4.0 |
| React Hook Form | Form management | 7.66.1 |
| Zustand | State management | 5.0.8 |
| TanStack Query | Server state | 5.90.10 |
| Axios | HTTP client | 1.13.2 |
| Zod | Schema validation | 4.1.12 |
| Sonner | Toast notifications | 2.0.7 |
| next-themes | Theme management | 0.4.6 |
| shadcn/ui | Component library | Latest |
| Lucide React | Icons | 0.554.0 |
- Node.js 20+ and npm/yarn/pnpm
- Git for version control
- Clone the repository
git clone https://github.com/your-username/your-repo-name.git
cd your-repo-name
# or
pnpm dev- Install dependencies
npm install
# or
yarn install
# or
pnpm install- Set up environment variables
Create a .env.local file in the root directory:
# External API Base URL (required)
API_URL=https://api.example.com # require for the app to run if u dont have one use a fake one to run the app or remove its use from next.config.ts
# External API Base URL (optional)
NEXT_PUBLIC_EXTERNAL_API_URL=https://api.yourdomain.com
# Add other environment variables as needed- Run the development server
npm run dev
# or
yarn dev
# or
pnpm dev- Open your browser
Navigate to http://localhost:3000 to see your application.
This structure is designed to be scalable, with clear separation of app routes, shared UI, domain features, and configuration.
├── src/
│ ├── app/ # Next.js app directory
│ │ ├── layout.tsx # Root layout with providers
│ │ ├── page.tsx # Home page
│ │ ├── example/ # Example pages
│ │ │ ├── page.tsx # Examples navigation hub
│ │ │ ├── data-table/ # DataTable examples
│ │ │ ├── dialog/ # Dialog examples
│ │ │ ├── dropdown/ # Dropdown/ActionMenu examples
│ │ │ ├── form/ # Form examples
│ │ │ ├── filters/ # Universal filters examples
│ │ │ ├── tabs/ # Tabs examples
│ │ │ └── toast/ # Toast & Tooltip examples
│ │ └── globals.css # Global styles
│ │
│ ├── components/
│ │ ├── common/ # Feature-focused UI (charts, dialog, dropdown, form, table, etc.)
│ │ ├── page/ # Page-level UI components
│ │ ├── ui/ # Reusable base UI components
│ │ └── ThemeToggle.tsx # Dark mode toggle
│ │
│ ├── config/ # App configuration
│ │ ├── query.client.config.ts # React Query configuration
│ │ └── rhf/ # React Hook Form defaults
│ │
│ ├── hooks/ # Custom hooks
│ │ ├── use-dialog.ts
│ │ └── shared/ # Shared hooks (debounce, storage, pagination, etc.)
│ │
│ ├── lib/ # Helpers & utilities
│ │ ├── http/ # API clients
│ │ ├── query-client.ts # React Query client
│ │ └── utils.ts # General utilities
│ │
│ ├── middlewares/ # Middleware system
│ │ ├── chain.ts # Middleware chaining utility
│ │ ├── auth-guard.middleware.ts # Authentication middleware
│ │ └── skip-static.middleware.ts # Skip static assets
│ │
│ ├── providers/ # App providers
│ │ ├── heroui.provider.tsx
│ │ ├── react-query.provider.tsx
│ │ └── theme.provider.tsx
│ │
│ ├── schema/ # Zod validation schemas
│ │ └── auth.schema.ts
│ │
│ ├── section/ # Page sections grouped by domain
│ │ ├── auth/
│ │ └── error/
│ │
│ ├── shared/ # Shared constants and styles
│ │ ├── constants/
│ │ └── styles/
│ │
│ ├── stores/ # Zustand stores
│ │ ├── auth.store.ts
│ │ ├── ui.store.ts
│ │ └── index.ts
│ │
│ └── types/ # TypeScript types
│ ├── index.ts
│ ├── pagination/
│ └── shared/
│
├── docs/ # Comprehensive documentation
├── examples/ # Example snippets
├── public/ # Static assets
└── scripts/ # Utility scripts
Comprehensive guides for all features:
| Documentation | Description | Link |
|---|---|---|
| Form System | Complete guide to all 13 form components, input types, validation, theming | View Docs |
| Modal/Dialog | Dialog system with per-button loading, async handlers, and customization | View Docs |
| Tooltip & Dropdown | CustomTooltip variants, ActionMenu with groups, checkboxes, submenus | View Docs |
| Middleware System | Middleware chaining, auth guard, rate limiting, logging, custom middleware setup | View Docs |
| Charts & Analytics | Compact ApexCharts-based sparklines and mini-bar charts with dashboard widgets | View Docs |
| API & Axios | HTTP clients setup, interceptors, error handling, authentication | View Docs |
| State & Utilities | Zustand stores, React Query, Toasts, Path constants | View Docs |
| Universal Filters | 13 filter types with URL sync, tabs/dropdown modes, TypeScript examples | View Docs |
| DataTable | Sortable, paginated data tables with selection and actions | View Docs |
Persist and sync state with localStorage. Supports SSR, override, and cross-tab updates.
const [value, setValue, removeValue] = useLocalStorage<string>(
"key",
"default",
);Persist and sync state with sessionStorage. Includes utility functions for direct access.
const [value, setValue, removeValue] = useSessionStorage<number>("key", 0);Debounce any value or state change for smoother UX and reduced API calls.
const debounced = useDebounce(searchTerm, 300);Universal pagination for server/client-side. Syncs with URL query params and exposes config.
const { pageIndex, pageSize, pagination } = usePagination();- 🎨 Form Components - Form System Documentation
- 🎯 Modal/Dialog - Modal & Dialog Documentation
- 💬 Tooltips & Dropdowns - Tooltip & Dropdown Documentation
- 🛡️ Middleware System - Middleware Documentation
- 🌐 API Calls - API Documentation
- 🗄️ State Management - State & Utilities Documentation
Visit the /example page for the examples hub, with links to:
| Route | Description |
|---|---|
| /example/data-table | DataTable with sorting, selection, actions, pagination |
| /example/dialog | Modal dialogs with async handlers & per-button loading |
| /example/dropdown | ActionMenu with groups, checkboxes, radios, submenus |
| /example/form | All form components - inputs, selects, uploads, OTP |
| /example/toast | Sonner toasts & custom tooltips with variants |
| /example/filters | Universal filters with URL sync, 13 filter types |
- ✅ DataTable - Sorting, pagination, row selection, actions column
- ✅ Tooltips - Info, success, warning, error variants with sizes
- ✅ Dropdown Menus - Groups, checkboxes, radios, keyboard shortcuts
- ✅ Form Components - Floating labels, OTP, file uploads, validation
- ✅ Toast Notifications - Promise-based, multiple types
- ✅ Dark Mode - All components support both themes
import { useAuthStore } from "@/stores";
import { internalAPI } from "@/lib/http/internal-api";
import { toast } from "sonner";
function LoginForm() {
const { login } = useAuthStore();
async function handleLogin(data: LoginDto) {
try {
const response = await internalAPI.post("/auth/login", data);
login(response.data.user);
toast.success("Login successful!");
} catch (error) {
toast.error(error);
}
}
return <form onSubmit={handleLogin}>...</form>;
}import { useQuery } from "@tanstack/react-query";
import { internalAPI } from "@/lib/http/internal-api";
function UserList() {
const { data: users, isLoading } = useQuery({
queryKey: ["users"],
queryFn: async () => {
const response = await internalAPI.get("/users");
return response.data;
},
});
if (isLoading) return <div>Loading...</div>;
return (
<div>
{users.map((user) => (
<UserCard user={user} />
))}
</div>
);
}import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { RHFUniversalInput } from "@/components/form";
import { loginSchema } from "@/schema/auth.schema";
function LoginForm() {
const { control, handleSubmit } = useForm({
resolver: zodResolver(loginSchema),
});
return (
<form onSubmit={handleSubmit(onSubmit)}>
<RHFUniversalInput
control={control}
name="email"
type="email"
label="Email"
placeholder="Enter your email"
/>
<RHFUniversalInput
control={control}
name="password"
type="password"
label="Password"
showPasswordToggle
/>
<button type="submit">Login</button>
</form>
);
}import { useDialog } from "@/hooks/useDialog";
import { toast } from "sonner";
function UserManagement() {
const deleteDialog = useDialog({
title: "Delete User",
subtitle: "This action cannot be undone.",
size: "md",
cancelButton: {
label: "Cancel",
},
actionButton: {
label: "Delete",
variant: "destructive",
onClick: async () => {
try {
await internalAPI.delete(`/users/${userId}`);
toast.success("User deleted successfully");
} catch (error) {
toast.error("Failed to delete user");
}
},
},
});
return (
<div>
<button onClick={deleteDialog.openDialog} className="text-red-600">
Delete User
</button>
{deleteDialog.dialog}
</div>
);
}Features:
- ✅ Automatic loading state during async operations
- ✅ Per-button loading control
- ✅ Type-safe dialog configuration
- ✅ Easy to override config when opening
- ✅ Built-in form support
- ✅ Multiple button variants
-
Start development server
npm run dev
-
View example page
- Navigate to http://localhost:3000/example
- See all form components and toasts in action
-
Read the documentation
- Form System - Learn about all form components
- API Integration - Set up API calls
- State Management - Use Zustand & React Query
-
Build your features
- Use pre-built components
- Follow the established patterns
- Refer to examples in
/example
# Development
npm run dev # Start dev server
# Production
npm run build # Build for production
npm run start # Start production server
# Code Quality
npm run lint # Run ESLint// app/dashboard/page.tsx
export default function DashboardPage() {
return <div>Dashboard</div>;
}// lib/services/post.service.ts
import { internalAPI } from "@/lib/http/internal-api";
export const postService = {
async getAll() {
const response = await internalAPI.get("/posts");
return response.data;
},
// Add more methods...
};// stores/post.store.ts
import { create } from "zustand";
export const usePostStore = create((set) => ({
posts: [],
setPosts: (posts) => set({ posts }),
}));// shared/constants/paths.ts
export const APP_PATHS = {
// ... existing paths
DASHBOARD: "/dashboard",
SETTINGS: "/settings",
};The ThemeToggle component provides flexible theme switching with multiple variants.
import { ThemeToggle } from "@/components/ThemeToggle";
export default function Header() {
return (
<header>
<ThemeToggle variant="click-small" />
</header>
);
}<ThemeToggle variant="click-small" />- Compact button design
- Perfect for headers/navigation
- Single click to toggle theme
<ThemeToggle variant="slide" />- Animated slide switch design
- More prominent visual feedback
- Great for settings pages
| Prop | Type | Default | Description |
|---|---|---|---|
variant |
"slide" | "click-small" |
"click-small" |
Theme toggle style |
- Uses
next-themesfor theme management - Syncs across all browser tabs
- Persists theme preference to localStorage
- Respects system theme preference on first visit
- Hydration-safe (prevents hydration mismatch)
All form components automatically respond to theme changes:
- Text inputs, selects, textareas
- OTP input boxes
- File uploads
- Checkboxes and radio groups
- Labels and error messages
- Editor with syntax highlighting on links
Edit your Tailwind config to customize light/dark mode colors:
// tailwind.config.js
export default {
darkMode: "class",
theme: {
extend: {
colors: {
// Custom colors for light mode
// Custom colors for dark mode
},
},
},
};import { useTheme } from "next-themes";
export function ThemeController() {
const { theme, setTheme } = useTheme();
return (
<div>
Current theme: {theme}
<button onClick={() => setTheme("light")}>Light</button>
<button onClick={() => setTheme("dark")}>Dark</button>
</div>
);
}Contributions are welcome! If you'd like to improve this starter template:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
If you find this starter helpful, please consider giving it a star on GitHub! It helps others discover this template.
This project is licensed under the MIT License - see the LICENSE file for details.
- Next.js Team - For the amazing framework
- shadcn - For the beautiful component library
- TanStack - For React Query
- Sonner - For beautiful toasts
Built with ❤️ by developers, for developers
Ready to start building? View Examples →