Skip to main content
TailStack’s frontend architecture combines cutting-edge technologies for a lightning-fast development experience and exceptional user interfaces.

Technology Stack

Vite 7

Next-generation frontend tooling with instant HMR

React 19

Latest React with improved performance and features

Tailwind CSS 4

Utility-first CSS with OKLCH color space

Shadcn UI

Accessible, customizable component system

Package Versions

Extracted from packages/core/source/frontend/package.json:
package.json
{
  "dependencies": {
    "@tailwindcss/vite": "^4.1.18",
    "axios": "^1.7.9",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "lucide-react": "^0.562.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "react-router-dom": "^7.12.0",
    "sonner": "^2.0.7",
    "tailwind-merge": "^3.4.0",
    "tailwindcss": "^4.1.18"
  },
  "devDependencies": {
    "@vitejs/plugin-react": "^5.1.1",
    "typescript": "~5.9.3",
    "vite": "^7.2.4"
  }
}

Vite Configuration

TailStack uses Vite 7 with optimized settings for React development:
vite.config.ts
import path from "path"
import tailwindcss from "@tailwindcss/vite"
import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"

export default defineConfig({
  plugins: [react(), tailwindcss()],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
})
Plugins:
  • @vitejs/plugin-react - Enables React Fast Refresh and JSX transformation
  • @tailwindcss/vite - Tailwind CSS 4 integration (replaces PostCSS setup)
Path Aliases:
  • @/* maps to ./src/* for cleaner imports
  • Example: import { Button } from '@/components/ui/button'

TypeScript Configuration

The frontend uses project references for better build performance:
tsconfig.json
{
  "files": [],
  "references": [
    { "path": "./tsconfig.app.json" },
    { "path": "./tsconfig.node.json" }
  ],
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}
Project references enable faster incremental builds by splitting app code (tsconfig.app.json) from build tooling (tsconfig.node.json).

React 19 Features

TailStack leverages React 19’s latest capabilities:

Server Components Support

While TailStack uses Vite (not Next.js), the architecture is compatible with future React Server Component adoption:
// Ready for RSC migration when needed
import { Suspense } from 'react'

function UserProfile({ userId }: { userId: string }) {
  return (
    <Suspense fallback={<Skeleton />}>
      <UserData userId={userId} />
    </Suspense>
  )
}

Automatic Batching

React 19 automatically batches state updates for better performance:
function Counter() {
  const [count, setCount] = useState(0)
  const [flag, setFlag] = useState(false)
  
  // Both updates batched automatically - single re-render
  const handleClick = () => {
    setCount(c => c + 1)
    setFlag(f => !f)
  }
}

Tailwind CSS 4

TailStack uses Tailwind CSS 4 with the latest features and improvements.

OKLCH Color Space

Tailwind 4 uses OKLCH for perceptually uniform colors:
/* Automatic fallbacks for older browsers */
.bg-blue-500 {
  background-color: #3b82f6; /* sRGB fallback */
  background-color: oklch(0.6 0.24 264); /* Modern browsers */
}
OKLCH provides better gradients, more vibrant colors, and consistent perceived lightness across hues.

Vite Plugin Integration

Tailwind 4 replaces PostCSS with a native Vite plugin:
import tailwindcss from "@tailwindcss/vite"

export default defineConfig({
  plugins: [react(), tailwindcss()],
})
Benefits:
  • Faster builds (no PostCSS overhead)
  • Better HMR performance
  • Simpler configuration

CSS-First Configuration

No tailwind.config.js - configuration happens in CSS:
index.css
@import "tailwindcss";

@theme {
  --color-brand: oklch(0.7 0.15 250);
  --font-display: "Inter", sans-serif;
}

Shadcn UI Integration

TailStack includes Shadcn UI with Tailwind 4 compatibility.

Component Architecture

Shadcn UI provides copy-paste components (not a package dependency):
# Add components to your project
pnpm dlx shadcn@latest add button
pnpm dlx shadcn@latest add dialog
pnpm dlx shadcn@latest add dropdown-menu
Components are added to src/components/ui/ and can be fully customized.

Utility Functions

utils.ts
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}
The cn() function combines:
  • clsx: Conditional class names
  • twMerge: Intelligent Tailwind class merging
Example:
<Button className={cn(
  "bg-primary",
  isLoading && "opacity-50",
  className // User-provided classes override defaults
)} />

Class Variance Authority

Shadcn UI uses CVA for type-safe variant props:
import { cva } from "class-variance-authority"

const buttonVariants = cva(
  "inline-flex items-center justify-center rounded-md",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground",
        destructive: "bg-destructive text-destructive-foreground",
        outline: "border border-input",
      },
      size: {
        default: "h-10 px-4 py-2",
        sm: "h-9 px-3",
        lg: "h-11 px-8",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

React Router

TailStack uses React Router 7 for client-side routing:
import { createBrowserRouter, RouterProvider } from 'react-router-dom'

const router = createBrowserRouter([
  {
    path: "/",
    element: <Layout />,
    children: [
      { index: true, element: <Home /> },
      { path: "about", element: <About /> },
      { path: "users/:id", element: <UserProfile /> },
    ],
  },
])

function App() {
  return <RouterProvider router={router} />
}
import { Link, useNavigate, useParams } from 'react-router-dom'

function Example() {
  const navigate = useNavigate()
  const { id } = useParams()
  
  return (
    <div>
      <Link to="/users/123">User Profile</Link>
      <button onClick={() => navigate('/dashboard')}>
        Go to Dashboard
      </button>
    </div>
  )
}

Sonner Toast Notifications

Sonner provides beautiful, accessible toast notifications:
import { toast, Toaster } from 'sonner'

function App() {
  return (
    <>
      <YourApp />
      <Toaster position="top-right" />
    </>
  )
}

function Example() {
  const handleSave = async () => {
    try {
      await saveData()
      toast.success('Saved successfully!')
    } catch (error) {
      toast.error('Failed to save', {
        description: error.message
      })
    }
  }
}

Success Toast

toast.success('Profile updated')

Error Toast

toast.error('Something went wrong')

Loading Toast

toast.loading('Uploading...')

Promise Toast

toast.promise(uploadFile(), {
  loading: 'Uploading...',
  success: 'Uploaded!',
  error: 'Failed to upload'
})

Lucide React Icons

TailStack includes Lucide React for consistent, beautiful icons:
import { Check, X, Menu, Settings } from 'lucide-react'

function IconExample() {
  return (
    <div>
      <Check className="h-4 w-4 text-green-500" />
      <X className="h-4 w-4 text-red-500" />
      <Menu className="h-6 w-6" />
      <Settings size={24} strokeWidth={1.5} />
    </div>
  )
}
Lucide icons are tree-shakeable - only imported icons are included in the bundle.

Development Scripts

package.json
{
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  }
}

Running the Frontend

# Development server with HMR
pnpm dev

# Type-check and build for production
pnpm build

# Preview production build locally
pnpm preview

# Lint code
pnpm lint

Best Practices

src/
├── components/
│   ├── ui/              # Shadcn UI components
│   │   ├── button.tsx
│   │   ├── dialog.tsx
│   │   └── dropdown-menu.tsx
│   └── features/        # Feature-specific components
│       ├── UserProfile/
│       └── Dashboard/
├── lib/                 # Utilities
│   └── utils.ts
├── hooks/               # Custom React hooks
└── pages/               # Route components
  • Use React.lazy() for code splitting large components
  • Leverage Vite’s automatic code splitting for routes
  • Optimize images with modern formats (WebP, AVIF)
  • Use Suspense boundaries for loading states
  • Minimize bundle size with tree-shaking

Next Steps

Backend Stack

Learn about the Express 5 backend

Agent Skills

Explore pre-configured AI skills

Build docs developers (and LLMs) love