Lean frontend boilerplate for building React applications with Vite, TypeScript, Tailwind CSS v4, React Router v7, TanStack Query, React Hook Form, Zod, Axios, Framer Motion, and a shadcn-style UI layer.
This repository is intended as a pragmatic starting point for frontend projects that need:
- a clear app shell and routing boundary
- reusable UI primitives
- a centralized API layer
- typed server-state handling
- form and validation defaults
- a build pipeline that stays small and predictable
Current runtime behavior:
- bootstrap starts in
src/main.tsx - the app shell lives in
src/app/App.tsx - routes are declared in
src/app/routes.tsx BrowserRouter+Routesis the active routing strategy- TanStack Query is provided from
src/app/providers.tsx - loading and error boundaries are already wired
- React 19
- TypeScript with
strictmode - Vite 7
react-router-dom7@tanstack/react-query5axios
react-hook-formzod@hookform/resolvers
- Tailwind CSS v4
- CSS variables in
src/index.css - shadcn-style component structure in
src/components/ui class-variance-authorityclsxtailwind-mergelucide-reactframer-motion
- ESLint
- TypeScript compiler (
tsc)
- App shell with providers and error boundary pre-wired
- Route registration isolated in
src/app/routes.tsx - Lazy-loaded pages with
Suspensefallback - Centralized API client with normalized error handling
- TanStack Query integration pattern through
src/hooks/* - Reusable UI primitives and utility-first styling setup
- React Hook Form + Zod defaults for forms
- Import alias support via
@/* - Example landing page and starter API/query hook flow
- Node.js LTS
pnpm
pnpm installpnpm devVite will start the local dev server with HMR enabled.
pnpm buildThis runs:
tsc -b && vite buildpnpm previewRun these before handing off code changes:
pnpm lint
pnpm type-check
pnpm buildNotes:
- there is currently no
pnpm testscript - a test scaffold exists at
test/setup.ts
The API client supports:
VITE_API_BASE_URL=If VITE_API_BASE_URL is not set, requests fall back to window.location.origin.
.
├─ docs/
├─ public/
│ ├─ fonts/
│ ├─ icons/
│ └─ images/
├─ src/
│ ├─ app/
│ │ ├─ App.tsx
│ │ ├─ error-boundary.tsx
│ │ ├─ providers.tsx
│ │ ├─ query-client.ts
│ │ └─ routes.tsx
│ ├─ components/
│ │ ├─ features/
│ │ └─ ui/
│ ├─ hooks/
│ ├─ lib/
│ │ ├─ api/
│ │ └─ utils/
│ ├─ pages/
│ ├─ types/
│ ├─ index.css
│ └─ main.tsx
├─ test/
│ └─ setup.ts
├─ components.json
├─ eslint.config.js
├─ package.json
├─ tsconfig.json
└─ vite.config.ts
src/app/*: app shell, providers, query client, error boundary, route registrationsrc/pages/*: route-level compositionsrc/components/features/*: feature-level UI compositionsrc/components/ui/*: reusable presentational primitivessrc/hooks/*: reusable hooks, including query hookssrc/lib/api/*: endpoints, HTTP client, request helperssrc/lib/utils/*: low-level shared utilities such ascn()src/types/*: shared contracts reused across layers
Preferred dependency direction:
app -> pages -> components/features -> hooks -> lib -> types
/->src/pages/index.tsx*->src/pages/not-found.tsx
Shell fallbacks:
- loading ->
src/pages/loading.tsx - render error ->
src/pages/error.tsx
Recommended data flow:
- Define endpoints in
src/lib/api/endpoints.ts - Add request functions in
src/lib/api/queries.ts - Wrap requests in
src/hooks/*with TanStack Query - Consume hooks inside feature components or pages
axios is installed in the repository, but the current low-level HTTP client in src/lib/api/client.ts still wraps fetch. Keep domain requests flowing through that shared API layer until the transport is intentionally migrated.
Project-level documentation:
docs/rules.mddocs/workflow.mddocs/architecture.mddocs/coding-standards.mddocs/patterns.mddocs/api.md
If documentation conflicts with runtime, follow src/main.tsx, src/app/App.tsx, and src/app/routes.tsx.
- Keep route declarations in
src/app/routes.tsx - Reuse
src/components/ui/*before creating new primitives - Do not call raw
fetchoraxiosfrom pages or feature components for domain data - Use
.gitkeepfor placeholder directories instead of empty.tsor.tsxfiles