This skill should be used when the user asks to "create a component", "build a UI element", "add a button", "create a form", "build a modal", "add a card component", "create a layout", or is working with React components in a Next.js project.
This skill provides component development standards for Next.js 15 App Router projects using TypeScript, Tailwind CSS, and shadcn/ui. All components follow a consistent pattern for maintainability and performance.
src/components/shared/ComponentName.tsxsrc/app/(route)/components/ComponentName.tsxsrc/components/ui/ (modify existing)src/components/ComponentName/index.tsxEvery component MUST follow this exact pattern:
import { cn } from "@/lib/utils"
type CardProps = {
title: string
description?: string
children: React.ReactNode
className?: string
variant?: "default" | "outline" | "ghost"
}
export const Card = ({
title,
description,
children,
className,
variant = "default",
}: CardProps) => {
return (
<div
className={cn(
"rounded-lg border p-6",
variant === "default" && "bg-card text-card-foreground shadow-sm",
variant === "outline" && "border-2 bg-transparent",
variant === "ghost" && "border-none bg-transparent",
className
)}
>
<h3 className="text-lg font-semibold">{title}</h3>
{description && (
<p className="mt-1 text-sm text-muted-foreground">{description}</p>
)}
<div className="mt-4">{children}</div>
</div>
)
}
Use Server Component (default - no directive needed):
Add "use client" only when ANY of these apply:
className?: string for style extensionReact.ReactNode for children, not JSX.Elementvariant: "sm" | "md" | "lg" not isLarge: booleancn() helper from @/lib/utils for conditional classesbase → sm: → md: → lg: → xl:Prefer composition over prop drilling:
// GOOD - Composition
<Card>
<Card.Header>
<Card.Title>Title</Card.Title>
</Card.Header>
<Card.Content>Content</Card.Content>
</Card>
// AVOID - Too many props
<Card
title="Title"
subtitle="Sub"
headerIcon={icon}
footerAction={action}
// ...20 more props
/>
any type for propsindex as key in listsuseEffect for data fetching (use Server Component or React Query)var keyword