# 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
1st level of puns: 5 gold coins
2nd level of jokes: 10 gold coins
3rd level of one-liners: 20 gold coins
```
## 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 (
)
}
```
## Input Variants
### Input OTP
```tsx
import {
InputOTP,
InputOTPGroup,
InputOTPSeparator,
InputOTPSlot,
} from "@/components/ui/input-otp"
```
### Input with Icon
```tsx
import { Search } from "lucide-react"
```
### File Input
```tsx
```
### Input Group
```tsx
import { InputGroup, InputGroupText } from "@/components/ui/input-group"
https://USD
```
## Data-Slot Composition
Components use `data-slot` attributes for styling child elements:
```tsx
// Button automatically styles icons with data-slot
// Custom component using data-slot pattern
function CustomCard({ children }: { children: React.ReactNode }) {
return (
{children}
)
}
// Usage
This icon is automatically styled
```
**Common data-slot values:**
- `icon` - Icons within components
- `title` - Heading elements
- `description` - Descriptive text
- `action` - Action buttons or triggers
## Select Component
```tsx
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
// With form
(
Fruit
)}
/>
```
## Checkbox and Radio Groups
```tsx
// Checkbox
import { Checkbox } from "@/components/ui/checkbox"
// Radio Group
import { Label } from "@/components/ui/label"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"