EXEPERTAI LAB

Research alpha

Time Machine
EXEPERTAI LAB
GALLERY / COLLECTION
← Browse Astryx gallery
Button·component·@astryxdesign/core

Button

Button triggers an action when clicked. Use it for form submissions, confirmations, navigation, or any interaction that needs a clear call to action.

Open in Playground @astryxdesign/core/Button

Showcases and examples

6 documented examples

Button — Variants

All four button variants side by side: primary, secondary, ghost, and destructive. A quick visual reference for choosing the right variant.

Preview loads on approachPreview loads on approach
Exact source · button-showcase
// Copyright (c) Meta Platforms, Inc. and affiliates.

'use client';

import {Button} from '@astryxdesign/core/Button';
import {Stack} from '@astryxdesign/core/Layout';

export default function ButtonShowcase() {
  return (
    <Stack direction="horizontal" gap={3} vAlign="center">
      <Button label="Primary" variant="primary" />
      <Button label="Secondary" variant="secondary" />
      <Button label="Ghost" variant="ghost" />
      <Button label="Destructive" variant="destructive" />
    </Stack>
  );
}

Usage

Button triggers an action when clicked. Use it for form submissions, confirmations, navigation, or any interaction that needs a clear call to action.

  • Reserve primary for the single most important action in the view. Use secondary or ghost for everything else based on emphasis.
  • Write labels that describe the action ("Save changes", "Delete account", "Send invite"), not vague labels like "OK" or "Click here".
  • Show a loading state for actions that take time, like saving or submitting, so the user knows it is working.
  • Always provide a label for icon-only buttons so screen readers can announce what the button does. Add a tooltip for sighted users.
  • For a dedicated icon-only button, use IconButton from '@astryxdesign/core/IconButton'. It is a separate component, not exported from '@astryxdesign/core/Button'.
  • Place more than one primary button in the same view; this dilutes the visual hierarchy.
  • Use the destructive variant without a confirmation step for irreversible actions like deleting data.
  • Use a button for navigation. If it only takes the user to another page, use a link instead. Buttons are for actions like saving, deleting, or submitting.

Typed props

PropType and behavior
labelstring · required
Accessible label. Rendered as visible text by default; used as aria-label when isIconOnly is true.
variant'primary' | 'secondary' | 'ghost' | 'destructive' · default 'secondary'
Visual style variant.
size'sm' | 'md' | 'lg' · default 'md'
Size variant.
elevation'none' | 'low' | 'med' | 'high' · default 'none'
Resting shadow depth for floating buttons (e.g. a FAB). none is the default flat button; low/med/high map to the shadow token scale. Ignored inside a ButtonGroup, where elevation is owned by the group.
type'button' | 'submit' | 'reset' · default 'button'
HTML button type attribute.
namestring
HTML name attribute for form submission.
valuestring | number | readonly string[]
HTML value attribute for form submission.
formstring
Associates the button with a form element by ID.
isLoadingboolean · default false
Shows a loading spinner and disables interaction. Announces "Loading" via a live region.
isInterruptibleboolean · default false
Keep the button clickable while a clickAction is pending: the spinner and aria-busy still show, but the button is not disabled and the action is not deduped, so a re-click lands and interrupts the in-flight action with a fresh one.
isDisabledboolean · default false
Disables the button. When a tooltip is present, uses aria-disabled instead of native disabled so the button stays focusable.
iconReactNode
Icon element rendered before the label text. An Astryx Icon with no explicit size defaults to sm for sm/md buttons and md for lg buttons.
Slot: Icon
isIconOnlyboolean · default false
When true, renders as a square icon-only button with label as aria-label. Requires icon. Tip: for a dedicated icon-only button component, use IconButton from '@astryxdesign/core/IconButton' instead.
widthSizeValue
Width of the button. Numbers are treated as pixels, strings are used as-is (e.g., '100%' for a full-width button). By default the button sizes to its content.
childrenReactNode
Optional override for visible text. When provided, displayed instead of label, but label is still required (it provides the accessible name). For most cases, just use label alone: <Button label="Save" />.
endContentReactElement<IconProps> | ReactElement<BadgeProps>
Trailing icon or badge rendered after the label. Ignored when isIconOnly is true. Color is inherited from the button variant.
Slot: Icon, Badge
tooltipstring
Tooltip text shown on hover.
onClick(e: MouseEvent) => void
Standard click handler (passed through from ButtonHTMLAttributes).
clickAction(e: MouseEvent) => void | Promise<void>
Async click handler. Shows loading state while the returned promise is pending.
hrefstring
When provided, renders the button as a link element (<a> or custom link component). The destination follows the shared navigation rule described on the Link href prop.
asComponentType
Custom link component to use when href is provided (e.g. Next.js Link).
targetstring
HTML target attribute when rendered as a link (e.g. "_blank").
relstring
HTML rel attribute when rendered as a link (e.g. "noopener noreferrer").

Anatomy

Icon · optional

A leading icon that reinforces the label, like a trash icon on a Delete button.

Label · required

The visible text describing the action. Also used as the accessible name.

End content · optional

A trailing badge or icon after the label, like a notification count or dropdown arrow.

Spinner · optional

Replaces the icon during loading to show the action is in progress.

Accessibility

Text label

Color contrast · 1.4.3 Contrast (Minimum) · 4.5:1

Button text must have at least 4.5:1 contrast with the button background in every state. For Hover and Pointer down, measure the final background after the overlay is applied.

States: Rest, Hover, Pointer down

Essential icon or spinner arc

Color contrast · 1.4.11 Non-text Contrast · 3:1

An icon used instead of text must have at least 3:1 contrast with the button background. The moving spinner arc must also meet 3:1. An icon beside a visible label does not need its own check.

States: Icon only, Loading

Badge text

Color contrast · 1.4.3 Contrast (Minimum) · 4.5:1

Badge text inside a button must have at least 4.5:1 contrast with the Badge background. Check all 14 built-in Badge colors in Rest, Hover, and Pointer down on page and surface backgrounds. This covers 336 pairs per mode. Check custom end content separately.

States: Rest, Hover, Pointer down

Visible control boundary

Color contrast · 1.4.11 Non-text Contrast · 3:1 if needed

The button edge needs 3:1 contrast only when users need it to see the control. A text-only button can rely on its label.

States: Rest

Keyboard focus indicator

Color contrast · 1.4.11 Non-text Contrast · 3:1

The focus outline needs at least 3:1 contrast with the area around the button. Check every style. Destructive buttons use a red outline.

States: Focus visible

Disabled appearance

Color contrast · 1.4.3 and 1.4.11 exceptions · Not required

Disabled controls do not need to meet these contrast ratios.

States: Disabled

Theming

Targets

astryx-button

Visual props: size, variant, elevation

Variables

--_button-radius · private

Border radius

Default: var(--radius-element)

--button-focus-offset

Focus ring outline offset

Default: var(--focus-outline-offset)

--button-icon-only-aspect

Aspect ratio for icon-only buttons

Default: 1 / 1

Derived properties

borderRadius

Uses --_button-radius.