Button
Buttons trigger actions, in several hierarchies, colour families and sizes, with icon, loading and toggle states.
import { Button } from '@aksornproject/aksara-ui'Basic button
variant sets the hierarchy. primary is the default and the strongest. Use one primary action per view.
<Button>Primary</Button>
<Button variant="secondary-brand">Secondary</Button>
<Button variant="tertiary-brand">Tertiary</Button>
<Button variant="link-brand">Link</Button>Accent variants
Variants ending in -accent and tertiary-inverted use the accent set, a quieter neutral for secondary actions.
<Button variant="secondary-accent">Secondary accent</Button>
<Button variant="tertiary-accent">Tertiary accent</Button>
<Button variant="link-accent">Link accent</Button>Colors
color picks the family. brand and sub-brand take the brand variants. information, success, warning and destructive take primary, secondary, tertiary and link. TypeScript rejects a variant from the wrong set.
<Button color="sub-brand">Sub-brand</Button>
<Button color="information">Information</Button>
<Button color="success">Success</Button>
<Button color="warning">Warning</Button>
<Button color="destructive">Destructive</Button>
<Button color="destructive" variant="secondary">
Delete
</Button>Sizes
Six sizes, from xs (28px) to huge (60px). md is the default. Link variants keep the label line height.
<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="huge">Huge</Button>Icons
leadingIcon and trailingIcon render in sized boxes and inherit the text colour. iconOnly makes a square button. An icon-only button needs an aria-label.
<Button leadingIcon={<IconInterfaceEssentialSearchLoupe />}>
Search
</Button>
<Button
variant="secondary-brand"
trailingIcon={<IconInterfaceEssentialArrow />}
>
Next
</Button>
<Button
iconOnly
variant="tertiary-accent"
leadingIcon={<IconInterfaceEssentialTrashDeleteBin2 />}
aria-label="Delete"
/>Loading and disabled
loading hides the label, keeps the width and shows three dots. The button stays focusable with aria-disabled and aria-busy, and its click, key and pointer handlers do not run. disabled removes it from the tab order.
<Button loading={saving} onClick={save}>
Save
</Button>
<Button disabled>Disabled</Button>Toggle
aria-pressed drives the selected style, so a toggle needs no extra prop.
<Button
variant="tertiary-accent"
aria-pressed={bold}
onClick={() => setBold((value) => !value)}
>
Bold
</Button>Composition
render swaps the element. Pass nativeButton={false} when it is not a <button>, so Base UI adds role="button", the tab stop and Enter and Space activation. className merges last, so a token utility you pass replaces the default one.
<Button
nativeButton={false}
render={<a href="#composition" />}
variant="secondary-brand"
>
Link styled as a button
</Button>Accessibility
- Without
type, a Button inside a form submits it. Passtype="button"for other actions. loadingkeeps the label as the accessible name.- The focus ring shows on keyboard focus only.
forceFocusVisibleshows it while related UI, such as an open menu, holds the focus.
API
Button
Prop
Type