General · astro-ui · Button
Button
Action trigger with variants, sizes, loading states, and anchor mode.
Button is the workhorse of the library: a zero-JS action trigger that renders a <button> — or an <a> when href is set — with eleven variants, eight theme colors, seven sizes, four loading-spinner styles, and native form participation. Extra attributes forward untouched.
Features
- 11 variants: primary, secondary, outline, ghost, destructive, link, solid, dashed, soft, plain, pure
- 8 theme colors via `color`: primary, secondary, destructive, success, warning, info, carbon, accent
- 7 sizes: xs, sm, md, lg, xl, 2xl, icon (icon requires ariaLabel)
- Loading state with 4 spinner styles (ring, dots, pulse, spin) and 3 positions
- Invalid state: error border + red focus ring + aria-invalid
- Anchor mode via href — links keep rel/target support
- Native form participation: form, formAction, formMethod='dialog'…
- shape (rounded/square/circle/pill) and shadow (sm/md/lg) controls
- leading / trailing icon slots
- TypeScript-typed, zero JS, token-themed
Usage
---
import { Button } from "astro-ui";
---
<Button>Primary</Button>
<Button variant="outline" href="/docs">Read docs</Button>
<Button color="success">Approve</Button>
<Button loading loadingIcon="dots">Saving…</Button>Demos
Basic
<Button>Primary</Button>Variant
<Button>Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="destructive">Destructive</Button>
<Button variant="link">Link</Button>
<Button variant="solid">Solid</Button>
<Button variant="dashed">Dashed</Button>
<Button variant="soft">Soft</Button>
<Button variant="plain">Plain</Button>
<Button variant="pure">Pure</Button>Color
<Button color="success">Success</Button>
<Button color="warning">Warning</Button>
<Button color="info">Info</Button>
<Button color="accent">Accent</Button>
<Button variant="outline" color="destructive">Outline danger</Button>
<Button variant="soft" color="info">Soft info</Button>Size
<Button size="xs">Extra small</Button>
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
<Button size="xl">Extra large</Button>
<Button size="2xl">2XL</Button>
<Button size="icon" ariaLabel="Search">⌕</Button>Loading
<Button loading>Submitting</Button>
<Button loading loadingPosition="center" loadingText="Saving…">Save</Button>
<Button loading loadingIcon="dots">Dots</Button>
<Button loading loadingIcon="pulse">Pulse</Button>Invalid
<Button invalid>Invalid state</Button>
<Button variant="outline" invalid>Invalid outline</Button>
<Button variant="ghost" invalid>Invalid ghost</Button>Shape & shadow
<Button variant="outline" shape="rounded">Round</Button>
<Button variant="outline" shape="circle" ariaLabel="Go">→</Button>
<Button variant="outline" shadow="md">Shadow md</Button>
<Button disabled>Disabled</Button>API
Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "primary" | "secondary" | "outline" | "ghost" | "destructive" | "link" | "solid" | "dashed" | "soft" | "plain" | "pure" | "primary" | Visual style; primary/secondary/destructive are solid shorthands. |
color | "primary" | "secondary" | "destructive" | "success" | "warning" | "info" | "carbon" | "accent" | — | Theme color for solid/soft and tinted outline-style variants; re-resolves legacy solid shorthands when set. |
size | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "icon" | "md" | icon is a square target — set ariaLabel. |
type | "button" | "submit" | "reset" | "submit" | Native default so form-wrapped buttons submit (method=dialog works zero-JS). Pass button for standalone controls. |
href | string | — | Renders <a> instead of <button>. |
disabled | boolean | false | Native disabled (button) / aria-disabled (link). |
loading | boolean | false | Disables + shows spinner + aria-busy. |
invalid | boolean | false | Error border + red focus ring + aria-invalid. |
loadingPosition | "start" | "center" | "end" | "start" | Spinner placement relative to content. |
loadingText | string | — | Replaces content when loadingPosition is center. |
loadingIcon | "ring" | "dots" | "pulse" | "spin" | "ring" | Spinner visual style. |
shape | "rounded" | "square" | "circle" | "pill" | "rounded" | Corner shape. |
shadow | "none" | "sm" | "md" | "lg" | "none" | Box-shadow token. |
fitContent | boolean | false | Fit content width instead of inline-flex. |
name / value | string | — | Native form participation, buttons only. |
form / formAction / formMethod / … | string | — | Form override attributes, buttons only. |
rel / target | string | — | Links only. |
class | string | — | Merged via cn(); Tailwind classes welcome. |
id | string | — | Element id. |
ariaLabel | string | — | Accessible name. |
Slots
| Slot | Description |
|---|---|
default | Button content (text, icons, etc.). |
leading | Rendered before the default content. |
trailing | Rendered after the default content. |
Accessibility
Implemented accessibility features — semantics, ARIA wiring, and keyboard behavior that ship with the component.
aria-busyannounces the loading state;aria-disabledkeeps disabled buttons focusable but inertaria-invalidstyling hook for form validation states- Loading spinner is
aria-hiddenwith:focus-visiblering
FAQ
How do I handle clicks?
Attach listeners app-side (the button ships zero JS): document.getElementById('save')?.addEventListener('click', …). Forms work with zero JS via type="submit".
When should I use loadingText?
With loadingPosition="center" the content is replaced entirely — loadingText provides the replacement label, e.g. "Saving…".
Does href change semantics?
Yes — the component renders a semantic <a> with link styling and forwards rel/target. Form attributes are ignored in anchor mode.
Changelog
Version history mentioning Button.
- General (7): Button, ButtonGroup, Command, Carousel, Clipboard, Kbd, Link.
- Shared
--ui-control-*scale (height, inline padding, radius) used by Button, Input, Select, Textarea, and InputGroup so controls align on a row.
- Button
shapeacceptsrounded | square | circle | pill(defaultrounded).