Explore all button variants, sizes, and states from the design system.
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
// Variant style
variant?:
| 'default' // Gray background, white text
| 'cta' // Primary blue, white text
| 'secondary' // Secondary color, white text
| 'success' // Green background, black text
| 'warning' // Orange background, dark text
| 'premium' // Juicy orange, black text
| 'error' // Red background, white text
| 'outline' // Transparent with border
| 'header' // Transparent, blue text
// Size
size?:
| 'default' // 48px height (h-12)
| 'small' // 32px height (h-8)
// Icon
icon?: React.ReactNode // Icon element (e.g., from lucide-react)
iconPosition?: 'left' | 'right' // Icon position (default: 'left')
// State
loading?: boolean // Shows spinner when true
disabled?: boolean // Disables button interaction
// Standard HTML button props
onClick?: (e: React.MouseEvent) => void
type?: 'button' | 'submit' | 'reset'
className?: string
children?: React.ReactNode
// ... all other HTML button attributes
}| Variant | Use Case | Colors | Preview |
|---|---|---|---|
| default | Standard actions | Gray 900 bg, white text | |
| cta | Primary call-to-action | Primary 500 bg, white text | |
| secondary | Secondary actions | Secondary 500 bg, white text | |
| success | Confirmations, positive actions | Success 400 bg, black text | |
| warning | Warnings, caution actions | Warning 500 bg, gray 900 text | |
| premium | Premium features, upgrades | Juicy orange 500 bg, black text | |
| error | Destructive actions, delete | Error 500 bg, white text | |
| outline | Secondary, cancel actions | Transparent bg, gray 900 border | |
| header | Navigation, header actions | Transparent bg, primary 500 text |
| Size | Height | Padding | Font Size | Icon Size |
|---|---|---|---|---|
| default | 48px (h-12) | 20px horizontal, 12px vertical | 16px (text-base) | 24px (h-6 w-6) |
| small | 32px (h-8) | 12px horizontal, 8px vertical | 12px (text-xs) | 16px (h-4 w-4) |
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | string | 'default' | Visual style of the button |
| size | 'default' | 'small' | 'default' | Size of the button (48px or 32px height) |
| icon | ReactNode | undefined | Icon to display (usually from lucide-react) |
| iconPosition | 'left' | 'right' | 'left' | Position of the icon relative to text |
| loading | boolean | false | Shows spinner and disables interaction |
| disabled | boolean | false | Disables button (opacity: 0.75) |
| onClick | function | undefined | Click handler callback |
| type | 'button' | 'submit' | 'reset' | 'button' | HTML button type attribute |
| className | string | undefined | Additional CSS classes |
| children | ReactNode | undefined | Button label/content |
loading=true, the button is automatically disableddefault
cta
secondary
success
warning
premium
error
outline
header
import { Button } from '@/components/ui/button'
// All available variants
<Button variant="default">Default</Button>
<Button variant="cta">CTA</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="success">Success</Button>
<Button variant="warning">Warning</Button>
<Button variant="premium">Premium</Button>
<Button variant="error">Error</Button>
<Button variant="outline">Outline</Button>
<Button variant="header">Header</Button>| Variant | Default | With Icon | Disabled | Loading |
|---|---|---|---|---|
| Default | ||||
| CTA | ||||
| Secondary | ||||
| Success | ||||
| Warning | ||||
| Premium | ||||
| Error | ||||
| Outline | ||||
| Header |
import { Button } from '@/components/ui/button'
import { Settings } from 'lucide-react'
// Default state
<Button variant="cta">Label</Button>
// With icon
<Button icon={<Settings />} variant="cta">Action</Button>
// Disabled state
<Button disabled variant="cta">Label</Button>
// Loading state (shows spinner)
<Button loading variant="cta">Loading</Button>import { Button } from '@/components/ui/button'
// Default size (48px height)
<Button variant="cta">Default Button</Button>
// Small size (32px height)
<Button size="small" variant="cta">Small Button</Button>import { Button } from '@/components/ui/button'
import { Settings, ChevronRight } from 'lucide-react'
// Icon on the left (default)
<Button icon={<Settings />} variant="cta">
Left Icon
</Button>
// Icon on the right
<Button icon={<ChevronRight />} iconPosition="right" variant="cta">
Right Icon
</Button>import { Button } from '@/components/ui/button'
function MyComponent() {
return (
<div className="flex gap-4">
<Button variant="cta">Click me</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
</div>
)
}import { Button } from '@/components/ui/button'
function MyComponent() {
const handleConfirm = () => {
// Your logic here
console.log('Confirmed!')
}
return (
<Button variant="success" onClick={handleConfirm}>
Confirm
</Button>
)
}import { Button } from '@/components/ui/button'
function MyForm() {
return (
<div className="max-w-md space-y-3">
<Button className="w-full" variant="cta">
Continue
</Button>
<Button className="w-full" variant="outline">
Go Back
</Button>
</div>
)
}import { Button } from '@/components/ui/button'
import { Crown, ChevronRight, X } from 'lucide-react'
function MyComponent() {
return (
<>
<Button icon={<Crown />} variant="premium">
Upgrade
</Button>
<Button icon={<ChevronRight />} iconPosition="right" variant="cta">
Next Step
</Button>
<Button icon={<X />} size="small" variant="error">
Delete
</Button>
</>
)
}import { Button } from '@/components/ui/button'
import { useState } from 'react'
function MyComponent() {
const [isLoading, setIsLoading] = useState(false)
const handleSubmit = async () => {
setIsLoading(true)
try {
await saveData()
} finally {
setIsLoading(false)
}
}
return (
<Button loading={isLoading} variant="cta" onClick={handleSubmit}>
Save Changes
</Button>
)
}