designComponents

Search the design system…

Search the design system…

primitives

Button

Trigger for the primary action on a screen. For navigation use a `<Link>` or the `link` variant; never wrap a route push in a button.

Buttons drive a single discrete action. The variant axis encodes priority and tone: there should be at most one `default`/`brand` per screen, with everything else ranking below it visually. Sizes match component density — `toolbar` and `xs` for compact tool strips, `default` and `lg` for primary forms and CTAs.

Install

Pull this component (and its dependencies) straight into your app via the shadcn CLI:

npx shadcn@latest add https://design.oapps.io/r/button.json

Or import from the workspace package:

import { Button } from "@8maverik8/design";

Examples

Variants

All shipped variants at default size, in priority order.

<Button>Save changes</Button>
<Button variant="secondary">Save draft</Button>
<Button variant="outline">Filter</Button>
<Button variant="ghost">Dismiss</Button>
<Button variant="destructive">Delete project</Button>
<Button variant="link">Learn more</Button>

Sizes

Match button height to component density.

<Button size="lg">Continue</Button>
<Button size="default">Continue</Button>
<Button size="sm">Continue</Button>
<Button size="xs">Continue</Button>

With icons

Icons sit inside; the button auto-tightens padding via `data-icon=inline-start|end` slots.

<Button>
  <Plus data-icon="inline-start" />
  Create campaign
</Button>
<Button variant="outline">
  Continue
  <ArrowRight data-icon="inline-end" />
</Button>
<Button variant="destructive" size="sm">
  <Trash2 data-icon="inline-start" />
  Delete
</Button>

Disabled

Always via the `disabled` prop — never via CSS.

<Button disabled>Save</Button>
<Button variant="destructive" disabled>Delete</Button>

Variants

variant

  • default(default)Primary action. Filled, monochrome (black on light, white on dark). Use for the single main action on a screen.
  • brandSame shape as default but never goes ghost when disabled — keeps a strong CTA presence in heroes / onboarding.
  • secondaryEqual-weight alternative next to a default button (e.g. Save / Cancel pairs).
  • outlineBordered low-emphasis action — good for filter chips, dropdown triggers, secondary toolbar buttons.
  • ghostNo chrome until hover. Use inside menus, table rows, dense toolbars where buttons should disappear when idle.
  • destructiveIrreversible operations: delete, purge, revoke. Tinted destructive surface — never use as a generic 'cancel'.
  • linkInline action that reads as a link. Prefer when the action sits inside a sentence.

size

  • default(default)32px tall — forms, dialogs, settings.
  • lg40px — heroes, marketing CTAs, onboarding.
  • sm28px — dense lists, inline row actions.
  • xs24px — chips, table-cell triggers.
  • toolbar26px (`--spacing-toolbar`) — diff/list toolbars.
  • icon | icon-sm | icon-xs | icon-lgSquare icon-only buttons; pair with `aria-label`.

Guidelines

  • Use exactly one `default` (or `brand`) button per screen — the primary action.Two filled buttons next to each other read as equal priority and the user has to think twice.
  • Use `destructive` for reversible actions like 'Cancel' or 'Discard draft'.Destructive tone trains users that the button is dangerous; using it for safe actions teaches them to ignore the warning.
  • Pair an icon with `aria-label` whenever the button has no visible text (icon variants).Screen readers announce nothing without it.
  • Disable a button via `pointer-events: none` or hidden CSS — always use the `disabled` prop.Custom disabled styling skips focus management and a11y semantics.
  • Use `asChild` to render the button as a `<Link>` when the action is navigation.Keeps semantics correct (right-click → open in new tab works) while inheriting button styling.