Buttoncomponent

Button(props: ButtonProps): ReactElement
ParamType
propsButtonProps
required
Return
ReactElement

Render either a <button> or an <a href=""> styled as a button, based on whether an onClick or href prop is provided.

  • Content-width by default (never grows); it won't shrink below its label. Pass full to fill the available width.
  • Accepts all ButtonVariants styling props plus the ClickableProps (onClick, href, disabled, etc.).

A clickable styled as a solid button. Renders an <a href=""> when given href, or a <button> when given onClick — the shared <Clickable> primitive picks the element, so a button is always the right semantics for what it does.

Things to know:

  • Content-width by default: it sizes to its label and never grows. Pass full to fill the available width (it then shrinks to share a row, down to the content floor).
  • strong marks the default action in a form — a filled background instead of an outline. plain and outline drop the background until hover/focus.
  • color= / status= move the tint anchor, so the background, border and label re-derive from the same ladder; small tightens the padding.
  • getButtonClass(variants) returns the same className the component composes — use it to style a non-<button> element as a button when Button itself doesn't fit.

Usage

Actions and links

tsx
import { Button } from "shelving/ui";

<Button onClick={save} color="primary" strong>Save</Button>
<Button href="/about">About</Button>
<Button onClick={remove} status="error">Delete</Button>

A row of buttons

tsx
import { Button } from "shelving/ui";
import { Row } from "shelving/ui";

<Row gap="small" right>
  <Button plain onClick={cancel}>Cancel</Button>
  <Button strong onClick={submit}>Continue</Button>
</Row>

Reusing the button class

tsx
import { getButtonClass } from "shelving/ui";

// Style an arbitrary element as a button.
<label className={getButtonClass({ color: "primary", small: true })}>
  Upload<input type="file" hidden />
</label>

Styling

Button paints from the tint ladder. Override these hooks at :root or any ancestor scope; move --button-tint to recolour the whole button, or use a per-property hook for one change.

VariableStylesDefault
--button-tintTint anchor for the button scopeinherit (flows from color= / status= / parent)
--button-backgroundSurface fillvar(--tint-90)
--button-hover-backgroundSurface fill on hover / focusvar(--tint-95)
--button-textLabel colourvar(--tint-50)
--button-borderBorder shorthandvar(--button-stroke) solid var(--tint-80)
--button-strokeBorder / outline thicknessvar(--stroke-normal) (2px)
--button-radiusCorner radiusvar(--radius-xsmall) (8px)
--button-paddingInner paddingvar(--space-small) (12px)
--button-small-paddingInner padding when smallvar(--space-xxsmall) (4px)
--button-spaceOuter block marginvar(--space-small) (12px)
--button-fontFont familyvar(--font-body)
--button-weightFont weightvar(--weight-strong) (700)
--button-sizeFont sizevar(--size-normal)
--button-leadingLine heightvar(--leading)
--button-transitionTransitionall var(--duration-fast) (150ms)
--button-focus-borderFocus outlinevar(--stroke-focus) solid var(--color-focus)
--button-disabled-opacityOpacity when disabled0.5
--button-strong-backgroundFill when strongvar(--tint-50)
--button-strong-textLabel colour when strongvar(--tint-100)
--button-strong-borderBorder when strongvar(--button-stroke) solid transparent
--button-strong-hover-backgroundHover fill when strongvar(--tint-55)

Global tokens it reads: the tint ladder --tint-50 / --tint-80 / --tint-90 / --tint-95 / --tint-100 / --tint-55, plus --space-small, --space-xxsmall, --radius-xsmall, --stroke-normal, --stroke-focus, --color-focus, --font-body, --weight-strong, --size-normal, --leading, and --duration-fast.

css
/* Theme: pill-shaped buttons. */
:root {
  --button-radius: 999px;
}

Examples

<Button onClick={save} color="primary">Save</Button>
<Button href="/about">About</Button>