OperantAI Workflow Design System
ComfortableCompact

Button (.ods-btn) is the primary way to commit an action. Per AGENTS.md's decision table, use -primary once per region — never more than one primary call-to-action in the same area — and reach for .ods-iconbtn instead for toolbar/row actions rather than a tiny text button.

Installation

HTML — already included if you loaded the 3 stylesheets. See the Installation guide.

React

npm install @operant/ui

@operant/ui is currently a monorepo workspace package, not yet published to the public npm registry.

Usage

HTML

<button type="button" class="ods-btn -primary">Approve</button>

React

import { Button } from "@operant/ui";

export default function Example() {
  return <Button>Approve</Button>;
}

Examples

All variants

Six variants: primary (default) for the one committed action in a region, secondary for supporting actions, ghost for low-emphasis actions in dense UI, danger/danger-ghost for destructive actions (solid vs. outlined emphasis), and success for a completed/positive commit.

<button type="button" class="ods-btn -primary">Primary</button>
<button type="button" class="ods-btn -secondary">Secondary</button>
<button type="button" class="ods-btn -ghost">Ghost</button>
<button type="button" class="ods-btn -danger">Danger</button>
<button type="button" class="ods-btn -danger-ghost">Danger ghost</button>
<button type="button" class="ods-btn -success">Success</button>
import { Button } from "@operant/ui";

<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="danger">Danger</Button>
<Button variant="danger-ghost">Danger ghost</Button>
<Button variant="success">Success</Button>;

Sizes

Three sizes: sm, md (default), lg.

<button type="button" class="ods-btn -primary -sm">Small</button>
<button type="button" class="ods-btn -primary">Medium</button>
<button type="button" class="ods-btn -primary -lg">Large</button>
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>;

Block width

block (React) / -block (HTML) stretches the button to 100% of its container — use for full-width actions in narrow layouts like a mobile composer footer or a modal footer that only has one action.

<button type="button" class="ods-btn -primary -block">Continue</button>
<Button block>Continue</Button>

Disabled

Native disabled reduces opacity to 50% and removes pointer events (.ods-btn:disabled).

<button type="button" class="ods-btn -primary" disabled>Approve</button>
<Button disabled>Approve</Button>

With a keyboard hint

ApprovalBar composes Button with a trailing <kbd> to surface its shortcut — the same pattern works anywhere a button has a global hotkey.

<button type="button" class="ods-btn -primary">Approve <kbd>A</kbd></button>
<Button variant="primary">
  Approve <kbd>A</kbd>
</Button>

API Reference

<Button>

Renders a native <button>.

PropTypeDefaultDescription
variant"primary" | "secondary" | "ghost" | "danger" | "danger-ghost" | "success""primary"Controls the visual style. primary is reserved for the single committed action per region.
size"sm" | "md" | "lg""md"Controls height, padding, and font size.
blockbooleanfalseStretches the button to 100% width.
classNamestring—Additional classes merged with the variant/size classes.
refRef<HTMLButtonElement>—Forwarded to the underlying <button>.

All other native <button> attributes (type, disabled, form, onClick, aria-*, data-*, etc.) are forwarded to the element.

HTML-side modifiers: .ods-btn (base) + one of -primary / -secondary / -ghost / -danger / -danger-ghost / -success, plus optional size (-sm / -lg; no suffix = md) and -block.

Accessibility

  • Renders as a native <button> — keyboard-focusable and operable via Enter or Space without any extra wiring.
  • Focus is visible only on keyboard navigation: .ods-btn:focus-visible applies --shadow-focus, following the :focus-visible spec rather than showing a ring on every mouse click.
  • disabled sets opacity: 0.5 and pointer-events: none together — always pair it with the native disabled attribute (not a visual-only class) so assistive tech reports the correct state.
  • Icon-only usage isn't a variant of this component — use .ods-iconbtn and give it an aria-label, per the decision table ("Toolbar/row action" → .ods-iconbtn, not a bare Button).
  • AGENTS.md #9 flags more than one -primary per region, and buttons used for navigation, as anti-patterns — use a real <a>/Link for navigation instead.