Button
Button separates an action’s semantic type from its visual hierarchy. The same API renders with Brutal or Elegant material without changing behavior. ButtonGroup joins related actions and can provide a shared size without changing each button’s semantic type.
Demos
Each behavior lives in its own TSX demo and rendered preview. Open a section’s source without wading through an unrelated all-in-one workbench.
Type and hierarchy
Compare all eight semantic types across the solid, secondary, tertiary, and quaternary hierarchy levels.
Size and shape
Tiny, small, medium, and large use the exact 22 / 28 / 34 / 40px height contract. Round and circle are independent shape controls.
Appearance
Ghost, dashed, text, borderless, strong, and block treatments share the same semantic type API. When independent hierarchy flags overlap, a fixed precedence decides which one applies.
Icon
Use a React node, a render callback, either placement, or an icon-only circle.
Send action
type="accent" is the action color, rUI’s pink, for the one action a surface exists for, such as sending a message. Press Enter in the composer to send.
Loading and disabled
Loading composes Raft UI’s Spinner, preserves the label and focus, and blocks mouse and keyboard activation without setting the native disabled attribute. The counter makes that input gate directly observable.
Custom color
Override the semantic fill and text colors for one-off product needs.
Tag, focus, and keyboard
Render native anchors or custom controls, control tab participation and keyboard activation, bridge Safari click focus, and keep native form types explicit.
ButtonGroup
Groups join adjacent actions, provide a shared size, and support horizontal or vertical layout without taking ownership of semantic type.
Props
Button
| Name | Type | Default | Description | Version |
|---|---|---|---|---|
type | default | tertiary | primary | accent | info | success | warning | error | default | Sets semantic intent and the matching color family. tertiary here is the neutral semantic type, not the hierarchy prop. | Unreleased |
secondary | boolean | false | Uses the semantic family’s soft surface. | Unreleased |
tertiary | boolean | false | Uses a quiet neutral surface with semantic text. | Unreleased |
quaternary | boolean | false | Removes the resting container while retaining hover and focus feedback. | Unreleased |
ghost | boolean | false | Uses a transparent surface with a semantic border. | Unreleased |
dashed | boolean | false | Uses the ghost treatment with a dashed border. | Unreleased |
text | boolean | false | Removes the control box and keeps only the label. | Unreleased |
bordered | boolean | true | Controls whether the current appearance renders its border. A borderless button is flat, with no shadow. | Unreleased |
color | string | undefined | Overrides the semantic color and derives hover, pressed, soft, and wave colors. A light hex or rgb() color gets dark text on its solid fill, so the label keeps AA contrast. | Unreleased |
textColor | string | undefined | Overrides the text and icon color for every state. | Unreleased |
size | tiny | small | medium | large | medium | Sets height, padding, type size, icon size, and radius. Heights are 22 / 28 / 34 / 40px. | Unreleased |
loading | boolean | false | Keeps the control focusable and its label visible, swaps the icon position to a spinner, marks the control busy, and blocks mouse and keyboard activation. | Unreleased |
loadingLabel | string | Locale’s “Loading” | The spinner’s accessible label. Defaults to the string from the current ConfigProvider locale. | Unreleased |
spinProps | Omit<SpinnerProps, "aria-label" | "role"> | undefined | Forwards Raft UI Spinner options such as size, variant, and native span props while Button retains ownership of the accessible loading status and label. | Unreleased |
disabled | boolean | false | Disables focus and activation. Alternate tags use equivalent ARIA and event behavior. | Unreleased |
focusable | boolean | true | Controls whether the control participates in focus navigation. | Unreleased |
keyboard | boolean | true | Controls Enter and Space activation while leaving pointer activation available. | Unreleased |
nativeFocusBehavior | boolean | Browser-dependent | Uses native click focus when available and otherwise applies Safari-compatible focus without scrolling. | Unreleased |
tag | React.ElementType | button | Renders another element such as an anchor while preserving matching native props and refs. | Unreleased |
block | boolean | false | Makes the button fill the available inline width. | Unreleased |
icon | ReactNode | undefined | Renders a decorative icon. Add aria-label to an icon-only button. | Unreleased |
renderIcon | () => ReactNode | undefined | Render callback. When both are supplied, it takes priority over icon; loading owns the icon slot without executing it. | Unreleased |
iconPlacement | left | right | left | Places the icon before or after the label. | Unreleased |
round | boolean | false | Uses a pill shape. | Unreleased |
circle | boolean | false | Uses a square footprint with a circular shape, intended for icon-only actions. | Unreleased |
strong | boolean | false | Selects the theme’s strong weight: Brutal 700 and Elegant 500, from defaults of 500 and 400. | Unreleased |
attrType | button | submit | reset | button | Sets the native button type attribute. | Unreleased |
secondary, tertiary, quaternary, ghost, dashed, and text are independent booleans. If flags overlap, resolution follows this order: text → dashed → ghost → secondary → tertiary → quaternary → solid. Native attributes, events, and refs are inferred from tag; native form behavior uses attrType. All exported Button and ButtonGroup contracts live in the component’s public-types.ts. Loading composes the public Raft UI Spinner: Brutal uses the hard border ring and Elegant uses the two-circle SVG arc, while Button keeps the label in place and blocks activation. The click wave is an Elegant-family material behavior and is deliberately absent from Brutal; the quiet secondary, tertiary, and quaternary treatments keep their ripple transparent.
ButtonGroup
| Name | Type | Default | Description | Version |
|---|---|---|---|---|
size | tiny | small | medium | large | undefined | Provides a shared size that overrides child button sizes. | Unreleased |
vertical | boolean | false | Stacks buttons vertically instead of horizontally. | Unreleased |
ButtonGroup supports native div attributes and refs. Give each group an accessible name with aria-label or aria-labelledby.