Button
Triggers an action or event. Supports 6 variants, 4 sizes, and can render as any HTML element via the asChild prop.
- ✓6 variants: default, secondary, outline, ghost, destructive, link
- ✓4 sizes: sm, default, lg, icon (square, for icon-only buttons)
- ✓First-class Lucide React icon support — icons are auto-sized and pointer-events disabled
- ✓asChild prop renders as any element via Radix Slot (avoids nested button/anchor issues)
- ✓Full keyboard accessibility — focus ring, disabled state
- ✓Forwards ref to the underlying element
import { Button }from "@aetherstack/ui"
import { Button } from "@/components/ui/button"
export function ButtonDemo() {
return (
<div className="flex flex-wrap gap-3">
<Button>Default</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="destructive">Destructive</Button>
</div>
)
}Usage
Variants
Six visual variants covering the full range of action contexts.
Sizes
Four sizes. Use 'icon' for square icon-only buttons — always add aria-label.
Disabled state
Disabled buttons are non-interactive and visually dimmed.
As link (asChild)
Use asChild to render the Button as a different element. This avoids the invalid nested <button><a> pattern and keeps full button styling.
With icon
Place a Lucide icon before or after the label. Icons are auto-sized to 16px — no extra classes needed.
Icon-only buttons
Use size="icon" for square icon buttons. Always provide aria-label for screen readers.
Loading state
Combine disabled with an animated Loader2 spinner for async actions.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | "default" | Controls the visual style of the button. |
| size | "default" | "sm" | "lg" | "icon" | "default" | Controls the padding and height. Use 'icon' for square icon-only buttons. |
| asChild | boolean | false | When true, renders the button's children as the root element using Radix Slot. Useful for rendering as <a>, <Link>, or other elements. |
| disabled | boolean | false | Disables the button — prevents pointer events and applies reduced opacity. |
| className | string | — | Additional class names merged onto the button element. |
| ...props | React.ButtonHTMLAttributes<HTMLButtonElement> | — | All standard HTML button attributes (onClick, type, aria-*, data-*, etc.) are forwarded to the element. |
* Required props
Accessibility
- →Always provide a descriptive label for icon-only buttons via aria-label.
- →Keyboard accessible — activates with Enter and Space keys.
- →Focus ring uses the --ring token and is always visible on keyboard navigation (focus-visible).
- →Disabled state removes pointer events entirely — does not trap focus.
- →When using asChild with <a>, the element becomes a link — screen readers announce it as a link, not a button. This is correct semantic behavior.