Best practices for using shadcn/ui components and styling in the Next.js project.
This project uses shadcn/ui on top of TailwindCSS 4 and Radix UI, within a Next.js 16 App Router + TypeScript (strict) setup.
@/components/ui/. Never hand-roll what shadcn already provides.
<Button> not <button className="...">.<Dialog> for modals, <Sheet> for slide-overs, <ScrollArea> for scrollable regions.bg-primary, text-muted-foreground, border, bg-card) — never hardcode bg-blue-500 etc. This ensures dark/light mode works..tsx. Define prop interfaces explicitly.// Page container
<div className="flex flex-col h-full w-full">...</div>
// Sidebar + main split
<div className="flex h-screen">
<aside className="w-64 border-r">...</aside>
<main className="flex-1 overflow-auto">...</main>
</div>
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
<Card>
<CardHeader><CardTitle>Title</CardTitle></CardHeader>
<CardContent>Content</CardContent>
</Card>
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent>
<DialogHeader><DialogTitle>Confirm Delete</DialogTitle></DialogHeader>
<DialogFooter>
<Button variant="outline" onClick={() => setOpen(false)}>Cancel</Button>
<Button variant="destructive" onClick={handleDelete}>Delete</Button>
</DialogFooter>
</DialogContent>
</Dialog>
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Label } from "@/components/ui/label";
<div className="space-y-2">
<Label htmlFor="name">Name</Label>
<Input id="name" value={name} onChange={e => setName(e.target.value)} />
</div>
npx shadcn@latest add [component-name]
# Component is added to frontend/components/ui/[component-name].tsx
Import: import { Component } from "@/components/ui/component"
frontend/app/globals.css.next-themes — already set up in components/theme-provider.tsx.tailwind.config colors directly unless adding a new semantic token.lucide-react only. Add aria-label to icon-only buttons for accessibility.<Sheet> from shadcn/ui for slide-over sidebar (check useIsMobile() hook in hooks/use-mobile.ts).sidebarOpen in hooks/stores/use-app-store.ts.