YA Button
Interactive button component with primary, secondary, tertiary, ghost, and destructive variants
The YaButton is the primary interactive element in the YaVendio Design System. It supports multiple variants, sizes, icons, loading states, and the selected state for toggle-like interactions.
Quick Start
pnpm dlx shadcn@latest add @yavendio/ya-buttonnpx shadcn@latest add @yavendio/ya-buttonyarn dlx shadcn@latest add @yavendio/ya-buttonimport { YaButton } from '@/components/ui/ya-button'
export default function Example() {
return <YaButton>Click me</YaButton>
}Variants
Five visual variants for different contexts and actions.
| Variant | Usage | Description |
|---|---|---|
primary | Main CTA | Purple background with inset shadow, most prominent |
secondary | Secondary actions | Gray background with subtle shadow |
tertiary | Tertiary actions | Transparent with border, good visibility |
ghost | Toolbar/subtle actions | No background, appears on hover |
destructive | Dangerous actions | Red background for delete/remove operations |
<YaButton variant="primary">Primary</YaButton>
<YaButton variant="secondary">Secondary</YaButton>
<YaButton variant="tertiary">Tertiary</YaButton>
<YaButton variant="ghost">Ghost</YaButton>
<YaButton variant="destructive">Destructive</YaButton>Sizes
Three sizes for buttons with text, plus three icon-only sizes.
| Size | Height | Font Size | Icon Size | Usage |
|---|---|---|---|---|
lg | 40px | 14px | 16px | Prominent CTAs |
default | 32px | 14px | 16px | Standard buttons |
sm | 28px | 12px | 14px | Compact UIs, tables |
icon-lg | 40x40px | - | 16px | Large icon buttons |
icon | 32x32px | - | 16px | Standard icon buttons |
icon-sm | 24x24px | - | 14px | Compact icon buttons |
<YaButton size="sm">Small</YaButton>
<YaButton size="default">Default</YaButton>
<YaButton size="lg">Large</YaButton>Icons
Add icons to the left or right of the button text. Icons are automatically sized based on button size.
import { Plus, ArrowRight, Download } from 'lucide-react'
<YaButton leftIcon={<Plus />}>Add Item</YaButton>
<YaButton rightIcon={<ArrowRight />}>Continue</YaButton>
<YaButton leftIcon={<Download />} rightIcon={<ArrowRight />}>Download</YaButton>Works best with Lucide React. The component automatically clones and resizes icon elements.
Icon Only
For toolbar actions or compact UIs, use icon-only button sizes.
import { Search, Settings, Plus } from 'lucide-react'
<YaButton size="icon-sm" aria-label="Search"><Search /></YaButton>
<YaButton size="icon" aria-label="Settings"><Settings /></YaButton>
<YaButton size="icon-lg" aria-label="Add"><Plus /></YaButton>Always provide aria-label for icon-only buttons to ensure screen reader accessibility.
Loading State
Show a loading spinner when an action is in progress. The button is automatically disabled during loading.
const [loading, setLoading] = useState(false)
<YaButton loading>Loading</YaButton>
<YaButton loading={loading} onClick={() => setLoading(true)}>
{loading ? 'Saving...' : 'Save'}
</YaButton>Disabled State
Disable buttons that cannot be interacted with. Uses native disabled attribute with 50% opacity.
<YaButton disabled>Primary</YaButton>
<YaButton variant="secondary" disabled>Secondary</YaButton>
<YaButton variant="tertiary" disabled>Tertiary</YaButton>Ghost Variant
Ghost buttons are ideal for toolbars or groups where interaction is already implied.
<YaButton variant="ghost">Ghost Button</YaButton>
<YaButton variant="ghost" leftIcon={<Settings />}>Settings</YaButton>
<YaButton variant="ghost" size="icon" aria-label="Like"><Heart /></YaButton>Destructive Actions
Use destructive buttons for actions that permanently cause data loss.
import { Trash2 } from 'lucide-react'
<YaButton variant="destructive">Delete</YaButton>
<YaButton variant="destructive" leftIcon={<Trash2 />}>Delete Account</YaButton>Because destructive actions cannot be undone, use button hierarchy to reduce errors: pair a secondary destructive with a primary destructive in confirmation dialogs.
All Variants & Sizes
Examples
Button Group
<div className="flex gap-2">
<YaButton variant="primary">Save</YaButton>
<YaButton variant="secondary">Cancel</YaButton>
</div>Form Actions
<div className="flex justify-end gap-2">
<YaButton variant="tertiary">Cancel</YaButton>
<YaButton variant="primary" leftIcon={<Check />}>Confirm</YaButton>
</div>Toolbar with Icon Buttons
<div className="flex gap-1 rounded-lg border p-1">
<YaButton variant="ghost" size="icon" aria-label="Star"><Star /></YaButton>
<YaButton variant="ghost" size="icon" aria-label="Heart"><Heart /></YaButton>
<YaButton variant="ghost" size="icon" aria-label="Send"><Send /></YaButton>
</div>Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'primary' | 'secondary' | 'tertiary' | 'ghost' | 'destructive' | 'primary' | Visual style |
size | 'lg' | 'default' | 'sm' | 'icon-lg' | 'icon' | 'icon-sm' | 'default' | Button size |
selected | boolean | false | Toggle selected state (yellow ring) |
loading | boolean | false | Show loading spinner |
disabled | boolean | false | Disable button |
leftIcon | ReactNode | - | Icon on the left |
rightIcon | ReactNode | - | Icon on the right |
className | string | - | Additional classes |
Extends all standard <button> HTML attributes.
Accessibility
Best Practices
| Do | Don't |
|---|---|
Use primary for the main CTA | Multiple primary buttons in one area |
Use destructive for delete/remove actions | Red styling without destructive variant |
Provide aria-label for icon-only buttons | Icon buttons without accessible names |
| Show loading state during async actions | Allow multiple clicks during loading |
| Use button hierarchy in dialogs | Equal prominence for all options |
| Keep button text concise: "Save", "Delete" | Very long button labels |
TypeScript
import { type VariantProps } from 'class-variance-authority'
import { yaButtonVariants } from '@/components/ui/ya-button'
type ButtonVariant = VariantProps<typeof yaButtonVariants>['variant']
type ButtonSize = VariantProps<typeof yaButtonVariants>['size']