Skip to content
ArcadiaDesign
482913

TSX

CodeDisplay shows a short code on the device that asks; CodeInput takes it on the device that answers. The groups are spaced by a gap, never a character, so a copied code pastes cleanly. One real field sits under the boxes: paste, autofill of one-time codes and undo behave as in any input, and onComplete fires on the last character.

Secrets

KeyBlock sets a long secret on one line, with nothing drawn around it.

7K2M-QX9P-H4TR-B8WN-3FDZ-M6CJ-Y2VE

actions are icon buttons at the end of its first line; the screen's primary action stays in the screen's footer. onCopied hears a copy the person makes themselves (Cmd+C, the Edit menu's Copy, the context menu) when the selection holds the whole key.

7K2M-QX9P-H4TR-B8WN-3FDZ-M6CJ-Y2VE

Where one line does not fit, the key folds after perLine groups, never inside one. Each dash leads its group, so a fold carries it to the next line's start, where the key's edge hides it: no line ends on a dash that reads as a hyphen, and a selection still copies every dash.

Copy

CopyButton writes through copyText and shows the check only when the text really landed.

TSX

A product with a native clipboard registers it once with setClipboardBridge; everywhere else the browser's clipboard runs, then a hidden-field copy. clearAfterMs asks a native bridge to clear a secret it still holds.

CodeInput is one labelled text field (autocomplete="one-time-code"), so screen readers and password managers see a normal input; the boxes are decorative. invalid sets aria-invalid and the shake honours reduced motion. CodeDisplay and KeyBlock are named groups. CopyButton announces "Copied" or "Couldn't copy" in a polite live region.

CodeInput

length
numberDefault 6
Number of boxes.
kind
"numeric" | "alphanumeric"Default "numeric"
numeric takes digits only; alphanumeric takes letters and digits, upper-cased.
value
string
Controlled value (characters only, no separators).
defaultValue
stringDefault ""
Initial value when uncontrolled.
onValueChange
(value: string) => void
Every change, with the characters typed so far.
onComplete
(value: string) => void
Called once the last box is filled (typed, pasted or autofilled).
invalid
booleanDefault false
Draws the boxes in danger and, unless reduced motion is on, shakes them once each time it turns true.
disabled
booleanDefault false
autoFocus
booleanDefault false
group
numberDefault 3
Group split: a wider gap after every group boxes. 0 for none.
labelrequired
string
The accessible name ("Code from MacBook Air").
name
string
Form field name.
rootStyle
RootStyle
Typed StyleX override: layout only.

coderequired
string
The code, without separators ("482913").
group
numberDefault 3
Characters per visual group (a gap, never a character, separates them).
size
"md" | "lg"Default "lg"
lg for the one code a screen is about; md inside a row or a sheet.
label
stringDefault "Code"
What the code is, for assistive tech ("Code"): the group's name, never drawn.
rootStyle
RootStyle
Typed StyleX override: layout only.

valuerequired
string
The secret as it is written, groups joined by - ("ABCD-EFGH-JKLM").
perLine
numberDefault 4
Groups per line once the key no longer fits on one. Default 4: a 7-group key folds into 4 and 3.
labelrequired
string
What the secret is, for assistive tech ("Recovery Key").
actions
ReactNode
Quiet actions at the key's end: icon buttons (Copy, Print), never the screen's primary action.
onCopied
() => void
A copy (Cmd+C, Edit > Copy, the context menu) whose selection holds the whole key.
rootStyle
RootStyle
Typed StyleX override: layout only.

textrequired
string | (() => string)
The text written to the clipboard (or a function that produces it at click time).
label
stringDefault "Copy"
The label at rest.
copiedLabel
stringDefault "Copied"
The label for COPIED_HOLD_MS after a copy that landed.
failedLabel
stringDefault "Couldn't copy"
The label after a copy the clipboard refused.
iconOnly
booleanDefault false
Draw only the glyph (an IconButton named by label).
clipboard
ClipboardWriteOptions
Clipboard options: clearAfterMs for a secret.
onCopied
(ok: boolean) => void
Called after every copy with whether it landed.
variant
"primary" | "secondary" | "outline" | "ghost" | "text" | "danger"Default "secondary"
primary is the monochrome ink CTA, for the one action that moves the flow forward (send).
size
"xs" | "sm" | "md" | "lg"Default "sm"
Heights 20 / 24 / 28 / 32.
shape
"rounded" | "pill"
tone
"neutral" | "plan"
plan is Plan mode's distance blue: a blue CTA on primary, blue text elsewhere. There is no amber tone: the sodium light is for literal lights (a running edge, a needs-you dot), never a control's fill.
iconEnd
IconName
hint
ShortcutSpec | ReactElement
Trailing key hint, drawn quietly: "⇧Tab", "⏎", ["⌘","K"], "mod+k", or a KbdGroup. Visual only (aria-hidden, so the name stays "Allow", not "Allow ⏎"); the keys are exposed as aria-keyshortcuts on the button. Binding the key is yours.
progress
number
Determinate progress, 0..1: a ring fills in the icon's slot (a download, an upload) while the label says the number. The button stays pressable; loading wins when both are set.
pressed
boolean
Toggle state: sets aria-pressed and data-pressed. Omit for a plain action button.
labelRow
boolean
The label is a row of parts (an avatar beside words), each on its capitals.
rootStyle
ButtonStyle
Typed StyleX override: where the button sits (margins, self-alignment, flex and grid placement, size bounds) and its --button-* knobs.
render
RenderProp<{ disabled: boolean }>
Replace the rendered element, e.g. render={<a href="/settings" />}, or a function of props and state.
disabled
boolean
Native disabled: no pointer events, no tooltip, skipped by Tab.
focusableWhenDisabled
boolean
Keep a disabled control focusable and hoverable (aria-disabled), so a tooltip can say why.
nativeButton
boolean
Button semantics, inferred from what renders: a <button> is native, an <a> stays a link, anything else gets role="button" and key handling. false forces button semantics on whatever renders (a link acting as a button).
className
string
A product's hook class for its own layout rules. Being retired: new code places a button with rootStyle; the call sites left are counted by ui.lint (kit-classname) and only go down.

Rest props go to <button> props.