# Component Patterns Reference ## Composition with asChild Use `asChild` to compose components without wrapper divs: ```tsx // Button as a Link (Next.js) import Link from "next/link" // Renders: Login // No wrapper div! // Button as a custom component // Dialog trigger with custom element
Custom trigger element
``` **When to use:** - Wrapping navigation links - Custom interactive elements - Avoiding nested buttons - Semantic HTML (button → link when navigating) ## Typography Patterns shadcn/ui typography scales using Tailwind utilities: ```tsx // Headings with responsive sizing

Taxing Laughter: The Joke Tax Chronicles

The People of the Kingdom

The Joke Tax

People stopped telling jokes

// Paragraph

The king, seeing how much happier his subjects were, realized the error of his ways.

// Blockquote
"After all," he said, "everyone enjoys a good joke."
// Inline code @radix-ui/react-alert-dialog // Lead text (larger paragraph)

A modal dialog that interrupts the user with important content.

// Small text Email address // Muted text

Enter your email address.

// List ``` ## Icons with Lucide ```tsx import { ChevronRight, Check, X, AlertCircle, Loader2 } from "lucide-react" // Icon sizing with components // Icons automatically adjust to button size // Icon-only button // Loading state // Icon with semantic colors // In alerts Error Your session has expired. ``` **Icon sizing reference:** - `size-3` - Extra small (12px) - `size-4` - Small/default (16px) - `size-5` - Medium (20px) - `size-6` - Large (24px) ## Form with React Hook Form Complete form example with validation: ```tsx "use client" import { zodResolver } from "@hookform/resolvers/zod" import { useForm } from "react-hook-form" import { z } from "zod" import { Button } from "@/components/ui/button" import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form" import { Input } from "@/components/ui/input" import { toast } from "sonner" // Define schema const formSchema = z.object({ username: z.string().min(2, { message: "Username must be at least 2 characters.", }), email: z.string().email({ message: "Please enter a valid email address.", }), bio: z.string().max(160).min(4), }) export function ProfileForm() { const form = useForm>({ resolver: zodResolver(formSchema), defaultValues: { username: "", email: "", bio: "", }, }) function onSubmit(values: z.infer) { toast.success("Profile updated successfully") console.log(values) } return (
( Username This is your public display name. )} /> ( Email )} /> ( Bio