Brik Design System
Components

Button

Trigger an event or action. The button family includes three components for different semantic needs.

The button family is three components for three semantic needs. Pick the right one before you reach for variants — the wrong shell semantically can't be fixed with styling.

Button

Use when: The action stays on this page (submit, open dialog, confirm).

Don't: Use it for navigation — right-click and keyboard nav break.

<Button>Save</Button>

LinkButton

Use when: The action navigates to a URL. Renders an `<a>` element.

Don't: Wrap a Button in a link — that breaks accessibility.

<LinkButton href="/docs">…</LinkButton>

IconButton

Use when: There's no visible text label. Single-icon trigger.

Don't: Downgrade emphasis when converting from Button — keep the variant.

<IconButton icon={…} label="Close" />

Use it for

  • Submitting a form
  • Confirming or cancelling a destructive operation
  • Opening a sheet, dialog, or popover
  • Triggering an immediate, synchronous action

Import

import { Button, LinkButton, IconButton } from '@brikdesigns/bds';

Anatomy

  1. 1
    Container

    The hit target. Sets size, padding, focus ring, and base variant styles.

  2. 2
    Leading icon

    Optional icon before the label. Use 1em sizing to scale with text.

  3. 3
    Labelrequired

    The accessible name of the button. Required for Button and LinkButton.

  4. 4
    Trailing icon

    Optional icon after the label. Common for "Continue →" or external-link affordances.

Variants

Twelve variants. Pick by action emphasis and destructive intent, not by aesthetics.

Standard ladder

highest emphasis → lowest
1
primary

Main call-to-action. One per section.

2
outline

Secondary emphasis. The "alongside primary" choice.

3
secondary

Tertiary, subtle. Supporting actions that don't compete.

4
ghost

Minimal emphasis. Repeated actions, navigation, dismiss.

Destructive ladder

Three flavors of destructive map onto the same ladder.

highest emphasis → lowest
1
danger

Primary destructive action — confirm dialogs, delete-and-go flows.

2
danger-outline

Destructive with less emphasis. Pairs with a non-destructive primary.

3
danger-ghost

Inline delete in lists, table rows, repeated remove affordances.

State variants

positive confirms a completed action. selected indicates the active option in a group. inverse and on-color are for placement on dark or branded surfaces.

Sizes

Five sizes. md is the default. Use sm only inside dense surfaces (table rows, popovers); use lg/xl for primary CTAs on landing pages.

Icons

Use iconBefore and iconAfter props. Icons should use 1em sizing to scale with the button's font size.

<Button iconBefore={<PlusIcon />}>Add item</Button>
<Button iconAfter={<ArrowRightIcon />}>Continue</Button>
<Button iconBefore={<DownloadIcon />} variant="outline">
  Export CSV
</Button>

Loading

The loading prop replaces button content with a spinner while preserving button width. The button is automatically disabled during loading.

<Button loading variant="primary">
  Saving...
</Button>

LinkButton

An <a> element styled as a button. Use when the action navigates to a URL. The href prop is required.

import { LinkButton } from '@brikdesigns/bds';

<LinkButton href="/docs" variant="outline">
  Read docs
</LinkButton>

<LinkButton
  href="https://github.com/brikdesigns/brik-bds"
  target="_blank"
  rel="noopener"
  iconAfter={<ExternalLinkIcon />}
>
  GitHub
</LinkButton>

IconButton

An icon-only button with a required label prop for accessibility. The label becomes the button's aria-label.

import { IconButton } from '@brikdesigns/bds';

<IconButton icon={<CloseIcon />} label="Close dialog" variant="ghost" />
<IconButton icon={<TrashIcon />} label="Delete item" variant="danger-ghost" />

Don't downgrade emphasis when converting Button → IconButton. A primary action stays a primary action. The 2026-04 IconButton-ghost regression came from agents converting <Button variant="primary"> into <IconButton variant="ghost">. Match the emphasis level, always.

When not to use

  • Don't use ghost for the only action on a page. Ghost is the lowest emphasis tier — it should appear alongside a higher-emphasis sibling.
  • Don't stack two primary buttons next to each other. Only one primary action per surface.
  • Don't use Button for navigation. If clicking takes the user to a new URL, use LinkButton so right-click + keyboard navigation work correctly.

Accessibility

  • Renders a real <button> element. Keyboard navigation, focus ring, and Enter / Space activation come from the platform.
  • Accessible name comes from the visible label. For IconButton, label becomes aria-label.
  • Disabled state uses the disabled attribute, which removes it from the tab order. For "blocked but explainable" actions, prefer keeping it focusable and showing a tooltip.
  • Loading state announces via aria-busy and disables interaction without removing focus.

API

The full prop reference (with auto-extracted TypeScript types and live controls) lives in Storybook → Components/Action/Button. Summary below.

Button

PropTypeDefault
variantButtonVariant'primary'
sizeButtonSize'md'
iconBeforeReactNode
iconAfterReactNode
loadingbooleanfalse
fullWidthbooleanfalse
disabledbooleanfalse

LinkButton

PropTypeDefault
hrefstring (required)
variantButtonVariant'primary'
sizeButtonSize'md'
iconBeforeReactNode
iconAfterReactNode
fullWidthbooleanfalse

IconButton

PropTypeDefault
iconReactNode (required)
labelstring (required)
variantButtonVariant'ghost'
sizeButtonSize'md'
loadingbooleanfalse

Type unions

type ButtonVariant =
  | 'primary' | 'outline' | 'secondary' | 'ghost'
  | 'inverse' | 'on-color'
  | 'danger' | 'danger-outline' | 'danger-ghost' | 'destructive'
  | 'positive' | 'selected';

type ButtonSize = 'tiny' | 'sm' | 'md' | 'lg' | 'xl';

CSS Override API

Component-scoped CSS variables exposed on .bds-button. Set these on a wrapping element or directly on the button to override without touching BDS internals.

VariableDefaultControls
--button-active-translate-y1pxDownward shift on :active press
--button-focus-outline-width2pxFocus ring stroke width
--button-focus-outline-offset2pxGap between button edge and focus ring
/* Example: flatten press effect in a toolbar context */
.my-toolbar {
  --button-active-translate-y: 0;
  --button-focus-outline-width: 3px;
}

On this page