Styling
How to style and customize FoundryKit primitives
Styling
FoundryKit primitives are built with Tailwind CSS and class-variance-authority (CVA) to provide flexible and consistent styling options.
Variants
Most primitives support multiple variants that change their visual appearance:
Button Variants
import { Button } from '@foundrykit/primitives'
function ButtonVariants() {
return (
<div className="space-x-2">
<Button variant="default">Default</Button>
<Button variant="destructive">Destructive</Button>
<Button variant="outline">Outline</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
</div>
)
}
Badge Variants
import { Badge } from '@foundrykit/primitives'
function BadgeVariants() {
return (
<div className="space-x-2">
<Badge>Default</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="destructive">Destructive</Badge>
<Badge variant="outline">Outline</Badge>
</div>
)
}
Sizes
Many components support different sizes:
Button Sizes
import { Button } from '@foundrykit/primitives'
function ButtonSizes() {
return (
<div className="space-x-2">
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
</div>
)
}
Input Sizes
import { Input } from '@foundrykit/primitives'
function InputSizes() {
return (
<div className="space-y-2">
<Input size="sm" placeholder="Small input" />
<Input size="md" placeholder="Medium input" />
<Input size="lg" placeholder="Large input" />
</div>
)
}
Custom Styling
Using Tailwind Classes
You can apply custom Tailwind classes to override or extend component styles:
import { Button, Card } from '@foundrykit/primitives'
function CustomStyling() {
return (
<div className="space-y-4">
{/* Custom button styling */}
<Button className="bg-gradient-to-r from-blue-500 to-purple-500 text-white hover:from-blue-600 hover:to-purple-600">
Gradient Button
</Button>
{/* Custom card styling */}
<Card className="border-2 border-dashed border-gray-300 bg-gray-50">
<div className="p-4">
<p>Custom styled card</p>
</div>
</Card>
</div>
)
}
Conditional Styling
Use conditional classes for dynamic styling:
import { Button } from '@foundrykit/primitives'
import { cn } from '@foundrykit/utils'
function ConditionalStyling({ isActive, isDisabled }) {
return (
<Button
className={cn(
"transition-all duration-200",
isActive && "ring-2 ring-blue-500 ring-offset-2",
isDisabled && "opacity-50 cursor-not-allowed"
)}
disabled={isDisabled}
>
Conditional Button
</Button>
)
}
Theme Integration
CSS Variables
Primitives use CSS variables for consistent theming. You can customize these in your CSS:
:root {
/* Color variables */
--color-primary: oklch(0.55 0.15 250);
--color-primary-foreground: oklch(0.98 0.005 250);
--color-secondary: oklch(0.95 0.01 250);
--color-secondary-foreground: oklch(0.15 0.08 250);
/* Border radius */
--radius: 0.5rem;
/* Spacing */
--spacing-1: 0.25rem;
--spacing-2: 0.5rem;
--spacing-3: 0.75rem;
--spacing-4: 1rem;
}
Dark Mode
Primitives automatically support dark mode when you configure Tailwind CSS:
@import "tailwindcss";
/* Dark mode variables */
@media (prefers-color-scheme: dark) {
:root {
--color-primary: oklch(0.65 0.15 250);
--color-primary-foreground: oklch(0.05 0.005 250);
--color-secondary: oklch(0.05 0.01 250);
--color-secondary-foreground: oklch(0.95 0.08 250);
}
}
Responsive Design
Responsive Variants
Use Tailwind's responsive prefixes to apply different styles at different breakpoints:
import { Button, Card } from '@foundrykit/primitives'
function ResponsiveDesign() {
return (
<div className="space-y-4">
<Button className="w-full sm:w-auto md:w-32 lg:w-48">
Responsive Button
</Button>
<Card className="p-2 sm:p-4 md:p-6 lg:p-8">
<p>Responsive padding</p>
</Card>
</div>
)
}
Mobile-First Approach
Design for mobile first, then enhance for larger screens:
import { Input, Label } from '@foundrykit/primitives'
function MobileFirstForm() {
return (
<div className="space-y-4">
<div className="space-y-2">
<Label htmlFor="email" className="text-sm sm:text-base">Email</Label>
<Input
id="email"
type="email"
className="text-sm sm:text-base h-8 sm:h-10"
placeholder="Enter your email"
/>
</div>
</div>
)
}
Animation and Transitions
Smooth Transitions
Add smooth transitions to interactive elements:
import { Button, Card } from '@foundrykit/primitives'
function AnimatedComponents() {
return (
<div className="space-y-4">
<Button className="transition-all duration-200 hover:scale-105 active:scale-95">
Animated Button
</Button>
<Card className="transition-all duration-300 hover:shadow-lg hover:-translate-y-1">
<div className="p-4">
<p>Hover to animate</p>
</div>
</Card>
</div>
)
}
Loading States
Style components for loading states:
import { Button, Skeleton } from '@foundrykit/primitives'
function LoadingStates({ isLoading }) {
if (isLoading) {
return (
<div className="space-y-2">
<Skeleton className="h-4 w-[200px]" />
<Skeleton className="h-10 w-[100px]" />
</div>
)
}
return (
<Button className="transition-opacity duration-200">
Loaded Button
</Button>
)
}
Best Practices
1. Use Semantic Colors
Prefer semantic color classes over hardcoded colors:
// ✅ Good - Uses semantic colors
<Button className="bg-primary text-primary-foreground hover:bg-primary/90">
// ❌ Avoid - Hardcoded colors
<Button className="bg-blue-500 text-white hover:bg-blue-600">
2. Maintain Consistency
Use consistent spacing and sizing throughout your application:
// ✅ Good - Consistent spacing
<div className="space-y-4">
<Input className="h-10" />
<Button className="h-10" />
</div>
// ❌ Avoid - Inconsistent sizing
<div className="space-y-4">
<Input className="h-8" />
<Button className="h-12" />
</div>
3. Leverage Design Tokens
Use design tokens for consistent theming:
// ✅ Good - Uses design tokens
<Card className="rounded-lg border border-border bg-card text-card-foreground">
// ❌ Avoid - Hardcoded values
<Card className="rounded-md border border-gray-200 bg-white text-gray-900">
4. Progressive Enhancement
Start with basic styles and enhance progressively:
function ProgressiveEnhancement() {
return (
<Button
className={cn(
"base-styles", // Always applied
"enhanced-styles", // Applied when supported
"advanced-styles" // Applied for advanced features
)}
>
Enhanced Button
</Button>
)
}
Next Steps
- Explore accessibility features to ensure your styled components are accessible
- Review best practices for optimal styling patterns
- Learn about component composition to build complex UI patterns