Customization
Blocks are built with flexibility in mind. Every component can be customized using Tailwind utility classes, CSS variables, and component props.
Understanding the Component Structure
All block components follow a consistent pattern using the cn() utility function for class merging:
import { cn } from "@/lib/utils"
function Component({ className, ...props }) {
return (
<div
className={cn(
"base-classes",
className
)}
{...props}
/>
)
}
The cn() function combines clsx and tailwind-merge to intelligently merge class names, allowing you to override default styles.
Customizing with Tailwind Classes
Override default styles
Pass custom classes through the className prop to override or extend default styles:import { Button } from "@/components/ui/button"
export default function Example() {
return (
<Button className="bg-blue-500 hover:bg-blue-600">
Custom Button
</Button>
)
}
Adjust spacing and layout
Modify spacing, sizing, and layout properties:import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"
export default function CustomCard() {
return (
<Card className="max-w-md p-8 gap-8">
<CardHeader className="gap-4">
<CardTitle className="text-3xl">Custom Spacing</CardTitle>
</CardHeader>
<CardContent className="space-y-6">
<p>Content with custom spacing</p>
</CardContent>
</Card>
)
}
Customize colors and borders
Apply custom colors, borders, and shadows:import { Badge } from "@/components/ui/badge"
export default function ColoredBadges() {
return (
<div className="flex gap-2">
<Badge className="bg-emerald-500 border-emerald-600">
Success
</Badge>
<Badge className="bg-amber-500 border-amber-600">
Warning
</Badge>
</div>
)
}
Using Component Variants
Many components use class-variance-authority (CVA) to provide predefined variants:
Modifying Component Layout
Components like Card use CSS Grid and Flexbox for layout. You can customize these:
import { Card, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
export default function GridCard() {
return (
<Card className="grid grid-cols-2 gap-4">
<CardHeader className="col-span-2">
<CardTitle>Two Column Layout</CardTitle>
<CardDescription>Custom grid layout</CardDescription>
</CardHeader>
<div className="p-6">Column 1</div>
<div className="p-6">Column 2</div>
</Card>
)
}
Responsive Customization
Use Tailwind’s responsive modifiers to create adaptive designs:
import { Button } from "@/components/ui/button"
export default function ResponsiveButton() {
return (
<Button
className="
w-full sm:w-auto
text-sm sm:text-base
px-4 sm:px-6 lg:px-8
"
>
Responsive Button
</Button>
)
}
Always test responsive customizations across different screen sizes to ensure a consistent user experience.
Input components support extensive customization:
import { Input } from "@/components/ui/input"
export default function CustomInput() {
return (
<div className="space-y-4">
<Input
placeholder="Custom styled input"
className="h-12 text-lg border-2 border-primary focus-visible:ring-4"
/>
<Input
placeholder="Rounded input"
className="rounded-full px-6"
/>
</div>
)
}
Real-World Example
Here’s a complete example from the Blocks codebase showing customization in action:
import { Button } from "@/components/ui/button"
import { Textarea } from "@/components/ui/textarea"
import { cn } from "@/lib/utils"
import { useState } from "react"
export default function CustomComposer() {
const [message, setMessage] = useState("")
const [isExpanded, setIsExpanded] = useState(false)
return (
<div
className={cn(
"w-full max-w-2xl mx-auto bg-transparent dark:bg-muted/50",
"p-2.5 shadow-lg border border-border transition-[border-radius]",
isExpanded ? "rounded-3xl" : "rounded-3xl"
)}
>
<Textarea
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Ask anything"
className="
min-h-0 resize-none rounded-none border-0 p-0
text-base placeholder:text-muted-foreground
focus-visible:ring-0 focus-visible:ring-offset-0
dark:bg-transparent
"
/>
<Button
type="submit"
size="icon"
className="rounded-full"
>
Send
</Button>
</div>
)
}
Use the cn() utility when you need to conditionally apply classes based on component state.
Best Practices
- Use Tailwind utilities first: Leverage Tailwind’s utility classes before writing custom CSS
- Preserve accessibility: Don’t remove focus indicators or ARIA attributes
- Test dark mode: Ensure customizations work in both light and dark themes
- Keep semantic structure: Maintain the component’s HTML structure for accessibility
- Use CSS variables: Reference theme variables for consistent theming
Next Steps