Actions

Button

Starts an action. Primary is cobalt on paper and paper on ink; there is deliberately no honey button.

Concept · live ReactSource file: tokens.jsonReact component: Button

Try it

Variant
Size
Theme
Disabled
<Button variant="primary" size="md">Start round</Button>

When to use

  • One primary button per view, for the action that moves the hive forward: Join, Start round, Send.
  • Secondary for a real alternative on paper: Copy join link.
  • Tonal for the second action on a dark surface, where an outline would vanish: Type instead, Start again. Filled, quiet, a full tap target.
  • Text for the quiet way out: Discard, End hive.
Don’t use it
  • A honey button. Honey is the voice, never a call to action.
  • A text link for an action on a phone: below a 44px target, it can't be tapped reliably.

Variants

Primary is cobalt on paper and paper on ink. Secondary carries a border-control edge, which holds 3:1.

primary
secondary
text
primary
secondary
tonal
text

States

Rest, hover, pressed, keyboard focus and disabled, for every variant, in both themes. Focus is a 2px ring outside a 2px ground-coloured gap, cobalt on paper and honey on ink, so it shows on every fill.

rest
hover
active
focus
disabled
primary
secondary
tonal
text
rest
hover
active
focus
disabled
primary
secondary
tonal
text

Sizes

sm · 32
md · 40
lg · 48

Content

  • Name the button by what happens: Start round, End round, Show readout.
  • The result repeats the verb: “Round started”.
  • Sentence case, no exclamation marks.

Accessibility

KeyWhat it does
TabMoves focus to the button.
Enter / SpaceRuns the action.
  • A native <button>, type="button" unless it submits a form. Disabled uses the disabled attribute, so it leaves the tab order.
  • Every size clears the 24px target in WCAG 2.2 (2.5.8): 32, 40 and 48px tall. Phones use 48.
  • An icon sits before the label and is hidden from screen readers; the label is the name. Button has no icon-only form.
  • Primary text holds 4.5:1 on its fill in both themes; the secondary edge (border-control) holds 3:1 against the ground.

Props

PropTypeDefaultDescription
variant'primary' | 'secondary' | 'tonal' | 'text''primary'Emphasis. Tonal is for the second action on a dark surface.
size'sm' | 'md' | 'lg''md'32, 40 or 48px. lg is for phones.
blockbooleanfalseFull width, for phone layouts.
iconReactNode—A 16px icon before the label, aria-hidden.
state'rest' | 'hover' | 'active' | 'focus'—Forces a state. For documentation matrices only.
…buttonButtonHTMLAttributes—onClick, disabled, type and the rest pass through.

Tokens

TokenValueWhere it lands
--hm-primary#1c2dad / #f6f7f9Primary button: cobalt on paper (the brand’s structure), paper on ink.
--hm-primary-hover#142380 / #d7d9ddHover and pressed state of the primary button.
--hm-on-primary#ffffff / #0b0e15Text and icons on the primary button.
--hm-border-control#7c798a / #7c8088Outlines of inputs and secondary controls. Holds 3:1 on bg and surface.
--hm-surface-hover#f1f0f4 / #2d323bHover and pressed fill for rows, ghost buttons and list items.
--hm-focus-ring#2d49c9 / #ffc550Keyboard focus: cobalt on paper, honey on ink, 2px outside a 2px bg gap.

Dialog

A short decision inside a device frame, like the laptop mute check.

Concept · live ReactSource file: tokens.jsonReact component: Dialog

Example

The laptop mute check, shown once per hive. Close it, then press Speak instead to open it again.

When to use

  • For a short decision that has to happen before the next step, like checking someone is muted.
Don’t use it
  • For information. Put it on the screen.
  • Twice for the same thing in one hive.

Content

  • The title says what’s about to happen. The body says what to do about it.
  • The primary button confirms in the person’s words: “I’m muted”. The text button keeps them where they were.

Accessibility

KeyWhat it does
Tab / Shift + TabMoves between the actions, and stays inside the dialog.
EscapeDismisses, the same as the text button.
Click outsideDismisses.
  • Opening moves focus to the primary action; closing hands it back to the control that opened it.
  • role="dialog" with aria-modal, named by its title.
  • A dialog that is already open when the page loads, like the one above, doesn’t take focus, so the page isn’t pulled down to it.

Props

PropTypeDefaultDescription
openboolean—Shown or not.
titlestring—One line, also the accessible name.
actionsReactNode—A text button, then the primary.
onDismiss() => void—Scrim click and Escape.

Tokens

TokenValueWhere it lands
--hm-surface-raised#ffffff / #2d323bThings that float: menus, dialogs, sheets, the record button at rest.
--hm-scrimrgba(20, 19, 24, 0.40) / rgba(10, 9, 13, 0.64)Overlay behind dialogs and bottom sheets.
--hm-text#141318 / #ebedefPrimary text. Light: graphite #141318 on paper, softer than black on white.
--hm-text-muted#5b5869 / #9b9fa5Secondary text: descriptions, helper text, metadata. Reads on every ground including surface-hover.
--hm-shadow-overlayring + 12/32 liftLifts the dialog off the scrim
--hm-radius-xl24pxCorners
widthmin(420px, 100%)Inside the device frame it opens in