Button

The primary action control.

Button is the single control for both actions and button-styled navigation. Given an href it renders a real anchor (<a>) — keeping middle-click, copy-link, and open-in-new-tab — and without one it renders a <button>. Either way the styling, variants, and states are identical.

import { Button } from '@base-org/bds-web/product/button';

<Button variant="primary" size="md">
  Continue
</Button>;

Variants

Primary

<Button variant="primary">Primary</Button>

Secondary

<Button variant="secondary">Secondary</Button>

Outline

<Button variant="outline">Outline</Button>

Ghost

<Button variant="ghost">Ghost</Button>

Negative

<Button variant="negative">Negative</Button>

Outline Negative

<Button variant="outline-negative">Outline Negative</Button>

Bare

<Button variant="bare">Bare</Button>
VariantUse for
primaryThe single most important action in a view.
secondarySupporting actions alongside a primary.
outlineActions on a busy or coloured background.
ghostLow-emphasis actions inside dense UI.
negativeDestructive actions, paired with a confirmation.
outline-negativeA destructive action that should not outweigh the primary action beside it.
bareText-only actions with no container or fixed height, such as a banner action or a close icon.

Sizes

Small is 32px tall with a 12px label, medium 36px with a 14px label, and large 48px with a 16px label.

Small

<Button size="sm">Small</Button>

Medium

<Button size="md">Medium</Button>

Large

<Button size="lg">Large</Button>

md is the default and the right choice inside forms and toolbars. Use lg for a standalone call to action, such as a section call to action on base.org, and sm for dense tables, inline controls and card footers.

Every button in a base.org hero is lg, including the secondary action beside the primary one, so the pair reads as one row.

Icons

With icons

<Button variant="secondary" startIcon={<PlusIcon />}>
New Project
</Button>
<Button variant="secondary" endIcon={<ArrowRightIcon />}>
Continue
</Button>

Icon Only

<Button variant="outline" startIcon={<PlusIcon />} aria-label="Add" />

startIcon and endIcon are sized to match the button. A button with only a startIcon and no children becomes a square icon-only button and needs an aria-label.

Arrows

Arrow

arrow appends an animated chevron in place of endIcon. On hover the shaft draws in and the arrow slides right; under reduced motion it is static. The chevron sits 4px closer to the edge than the label does on the other side.

<Button size="lg" arrow>Start Building</Button>
<Button size="lg" variant="secondary" arrow>Learn More</Button>

External Arrow

externalArrow appends a 9px ↗ for links that leave the site. With an href and no target, the link opens in a new tab with target="_blank" and rel="noopener noreferrer"; set target yourself to keep it in the same tab. Use it instead of arrow, not with it.

<Button href="https://docs.base.org" variant="outline" externalArrow>
Read The Docs
</Button>

Status

<Button status="pending">Saving</Button>
<Button status="success" successIcon={<CheckIcon />}>Saved</Button>

status moves an async action through idle → pending → success. pending shows the circle Spinner in the start slot and blocks presses. success hides the label and end icon and shows successIcon — there is no default glyph, so always pass one. Return to idle yourself once the moment has passed.

Pass href and Button renders an anchor with the same look and states. Use this for navigation. A link still shows the pending spinner but does not block presses, so keep status for buttons that run an action. LinkButton is deprecated in favour of this — see Link Button to migrate.

<Button href="/get-started" variant="primary">
Get Started
</Button>
<Button href="#" variant="secondary">
Learn More
</Button>

For an inline text link inside a sentence, use Link instead.

When to use

Use Button for any standalone action, and for button-styled navigation by passing href.

Use something else when:

  • The link sits inside a sentence. Use Link.
  • Several secondary actions on one object would crowd the surface. Collect them in a Menu.
  • The reader is choosing a value, not firing an action. Use Segment or Select.
  • It turns a setting on or off. Use Switch.

Usage

Do

Keep one primary button per view. If two actions look equally important, the view has not decided what it is for.

Don't

Use negative for anything reversible. It is reserved for actions that destroy data or cannot be undone.

  • Use arrow on the action that moves the reader forward, and leave it off the secondary action beside it.
  • Reserve externalArrow for destinations outside the site, so the ↗ keeps its meaning.
  • Content is centered by default. A justify-* class overrides it, for example justify-between on a full-width or Select trigger to start-align the label and push the end icon to the edge.

Props

PropTypeDefault
arrow

Appends an animated chevron in place of `endIcon`. Its shaft draws in and

TypebooleanDefaultfalse
children

The children of the component. A function may be provided to alter the children based on

Typestring | number | bigint | boolean | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ... 5 more ...Default—
className

The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the

TypeClassNameOrFunction<ButtonRenderProps>Default—
endIconTypeReactNode | ((renderProps: ButtonRenderProps) => ReactNode) | ((renderProps: LinkRenderProps) => ReactNode)Default—
externalArrow

Appends a small ↗ in place of `endIcon` for links that leave the site, and

TypebooleanDefaultfalse
href

A URL to link to. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#href).

TypestringDefault—
isDisabled

Whether the button is disabled.

TypebooleanDefault—
rel

The relationship between the linked resource and the current page. See

TypestringDefault—
sizeType"sm" | "md" | "lg" | nullDefaultmd
startIconTypeReactNode | ((renderProps: ButtonRenderProps) => ReactNode) | ((renderProps: LinkRenderProps) => ReactNode)Default—
statusType"idle" | "pending" | "success"Defaultidle
successIconTypeReactNodeDefault—
target

The target window for the link. See

TypeHTMLAttributeAnchorTargetDefault—
titleTypestringDefault—
type

The behavior of the button when used in an HTML form.

Type"button" | "submit" | "reset"Default'button'
variantType"outline" | "outline-negative" | "secondary" | "primary" | "negative" | "ghost" | "bare" | nullDefaultprimary

Accessibility

Button wraps React Aria's Button, so keyboard activation, focus management, and disabled semantics come from the primitive. Icon-only buttons must carry an accessible name via aria-label or aria-labelledby — in development, an icon-only button shipped without one logs a console warning.

Pressing scales the button down slightly, and colour changes skip their transition for keyboard focus. When the reader prefers reduced motion, the press scale, the icon/label crossfade, and the colour transitions all collapse to instant changes. A status change — idle → pending → success — is announced to screen readers through a visually-hidden role="status" region, not just the icon swap.

The arrow and externalArrow icons are decorative SVGs hidden from assistive technology, so the label alone must say where the button goes. The ↗ tells sighted readers a link opens a new tab; say so in the label when it matters.