Button

The action primitive. Extends Text with theme-driven variants and sizes.

Button extends Text, so it accepts every Text and Box prop. It adds a variant prop mapped to theme.skins.button and a $size prop mapped to theme.skins.button.sizes. Use it for actions; pass as="button" for a native button.

You have unsaved changes

Import#

typescript
import { Button } from "@reactberry/system/elements";

Usage#

typescript
import { Button } from "@reactberry/system/elements";

export default function SaveButton({ onSave }: { onSave: () => void }) {
  return (
    <Button as="button" type="button" variant="primary" onClick={onSave}>
      Save
    </Button>
  );
}

Examples#

Variants#

variant picks a style from theme.skins.button. Nested entries use a dot path, such as ghost.danger.

Sizes#

$size picks a size from theme.skins.button.sizes, which sets height, padding, font size and weight.

With icons#

Compose icons as children. Use gap for spacing and an icon.* size with shape="circle" for square icon buttons.

Disabled#

disabled dims the button and blocks pointer events. With as="button" the native disabled attribute is also set.

API#

Button#

PropTypeDefaultDescription
as
ElementType
"span"

Element or component to render. Use "button" for actions and "a" or a router link for navigation.

variant
string
"default"

Dot path into theme.skins.button.

$size
string
"medium"

Dot path into theme.skins.button.sizes. Pass "" to opt out of size styles.

disabled
boolean
—

Sets opacity: 0.5 and pointer-events: none, and is passed to the rendered element.

shape
string
"rounded"

Key in theme.shapes.

role
string
"button"

ARIA role.

tabIndex
number
0

Tab order.

Button also accepts every Text and Box prop. These defaults are applied before your props, so any of them can be overridden: border="none", display="inline-flex", alignItems="center", justifyContent="center" and cursor="pointer". A 0.2s ease transition is always applied.

Variant reference#

Variants resolve by dot path, so nested entries are used as ghost.dim or outline.dark. The default light theme defines:

  • default — with default.surface, default.danger, default.success, default.info, default.warning, default.accent
  • primary
  • accent
  • active
  • outline — with outline.danger, outline.dark, outline.dark.success, outline.dark.active
  • solid
  • ghost — with ghost.danger, ghost.subtle, ghost.dim, ghost.lighten
  • subtle — with subtle.darker
  • clean — no border, background, or radius
  • cta — with cta.subtle, cta.contrast
  • tab — top indicator bar, active when data-active="true"
  • segment — with segment.subtle
  • translucent — with translucent.light, translucent.dark
  • success, warning, danger — each with .light

The dark theme defines default, primary, outline, subtle, solid, ghost, clean, cta, danger, and bubble.

Size reference#

Light theme (font-weight: 600 throughout):

  • xxxsmall — height 1.5rem, font 0.875rem
  • xxsmall — height 1.75rem, font 0.875rem
  • xsmall — height 2rem, font 0.875rem
  • small — height 2.25rem, font 0.875rem
  • medium — height 2.5rem, font 1rem; medium.condensed uses 0.5rem horizontal padding
  • large — height 3rem, font 1.125rem

Square icon sizes: icon (2.5rem), icon.large (3rem), icon.small (2.25rem), icon.xsmall (2rem), icon.xxsmall (1.5rem).

The dark theme provides xxsmall to large with different font sizes and weights, adds xlarge (height 4rem), and has no xxxsmall. Padding for each size comes from theme.controlSizes (see Box).

Accessibility#

  • role="button" and tabIndex={0} are set by default, so the default span is announced as a button and can be focused.
  • Button adds no keyboard handling. A span with role="button" does not activate on Enter or Space; use as="button" for native keyboard and form behaviour.
  • With as="a", the default role="button" overrides the link role. Pass role={undefined} to keep link semantics.
  • disabled on a non-native element only blocks pointer events; the element stays focusable through tabIndex={0}.
  • Give icon-only buttons an aria-label.

Notes#

  • There are no built-in loading, icon, iconPosition, or fullWidth props. Compose children and use width="100%" instead.
  • Set type explicitly on native buttons inside forms.