Button

Triggers a click action usually performed by the user to trigger an event such as submitting a form or closing a dialog.

Anatomy

Import and assemble the component:

1import { Button } from '@raystack/apsara'
2
3<Button />

Usage

Variant

Four styles, in descending order of emphasis. Use solid for the one primary action on a screen, outline for secondary actions beside it, and ghost or text for actions that sit inside dense UI where a filled button would shout. Default is solid.

1<Flex gap={9}>
2 <Button variant="solid">Solid</Button>
3 <Button variant="outline">Outline</Button>
4 <Button variant="ghost">Ghost</Button>
5 <Button variant="text">Text</Button>
6</Flex>

Color

Color carries meaning, not decoration. danger for destructive actions, success for confirmations, neutral for actions that shouldn't compete for attention, accent for everything else. Default is accent.

1<Flex gap={9}>
2 <Button color="accent">Accent</Button>
3 <Button color="danger">Danger</Button>
4 <Button color="neutral">Neutral</Button>
5 <Button color="success">Success</Button>
6</Flex>

Size

Two sizes. normal is the default and fits most layouts. Use small inside toolbars, table rows, and other dense surfaces.

1<Flex gap={9} align="center">
2 <Button size="small">Small</Button>
3 <Button size="normal">Normal</Button>
4</Flex>

With icons

Pass leadingIcon, trailingIcon, or both. A leading icon reinforces the action; a trailing icon usually signals what happens next, like an arrow for navigation or a chevron for a menu.

1<Flex gap={9}>
2 <Button variant="solid" color="accent" leadingIcon={<>I</>}>
3 With leading icon
4 </Button>
5 <Button variant="solid" color="accent" trailingIcon={<>O</>}>
6 With trailing icon
7 </Button>
8 <Button
9 variant="solid"
10 color="accent"
11 leadingIcon={<>I</>}
12 trailingIcon={<>O</>}
13 >
14 With both icons
15 </Button>

Loading

loading swaps the content for a spinner and blocks further clicks, so an in-flight action can't be fired twice. Add loaderText to say what's happening — useful when the wait is longer than a second or two.

1<Flex gap={9}>
2 <Button variant="solid" loading>
3 Button
4 </Button>
5 <Button variant="solid" loading loaderText="Loading...">
6 Button
7 </Button>
8 <Button variant="outline" loading loaderText="Loading...">
9 Button
10 </Button>
11</Flex>

Disabled

disabled stops the button responding to any interaction. Default is false.

1<Flex gap={9}>
2 <Button variant="solid" disabled>
3 Solid
4 </Button>
5 <Button variant="outline" disabled>
6 Outline
7 </Button>
8 <Button variant="ghost" disabled>
9 Ghost
10 </Button>
11 <Button variant="text" disabled>
12 Text
13 </Button>
14</Flex>

Render as another element

render swaps the underlying element while keeping the button's styling and behavior. Use it for links that should look like buttons, so the browser still gives you middle-click, right-click, and open-in-new-tab.

1<Flex gap={9} align="center">
2 <Button render={<a href="/docs/components/link" />}>
3 Rendered as a link
4 </Button>
5 <Button variant="outline" render={<a href="/docs/components/link" />}>
6 Outline link
7 </Button>
8</Flex>

When the rendered element isn't a real <button>, nativeButton defaults to false so the correct role and keyboard handling are applied.

API Reference

Renders a clickable button element.

Prop

Type

Slots

Every rendered part carries a stable data-slot attribute for styling and testing:

SlotElement
buttonThe root <button> element
button-leading-iconWrapper around leadingIcon (when set and not loading)
button-trailing-iconWrapper around trailingIcon (when set and not loading)
button-loaderThe loading spinner (when loading)
button-loader-textWrapper around loaderText (when loading with loaderText)

Accessibility

  • Uses the native <button> element so keyboard activation with Enter and Space works out of the box.
  • Disabled state is communicated via the native disabled attribute.
  • Loading state sets aria-busy="true" on the button so screen readers announce the busy state. The internal spinner is rendered with aria-hidden="true" to avoid double-announcing.
  • Respects motion preferences: button loader rotation is enabled only when prefers-reduced-motion: no-preference.