Safety actions
The primary safety affordance for the active scope. Always one tap away. The destructive action takes a deliberate second tap.
Live
Try it. The primary action arms on the first tap and fires on the second within three seconds. Press Escape or the cancel chip to disarm.
Anatomy
Two affordances per scope: a secondary action (override / pause / suspend, scope-dependent) and a primary destructive action (e-stop / recall / abort). The primary action is the only one that arms on first tap.
Outlined, neutral. Single tap fires.
Filled with danger semantic. Never Ember — danger and identity are visually distinct.
Pulsing ring and label change to 'Confirm · X'. A second tap within 3s fires.
Floating dismiss. Esc also disarms.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| scope | SafetyScope | — | Command-context scope. Selects which primary and secondary actions surface. See Command contexts for the type definition. |
| onAction | (key: SafetyActionKey) => void | — | Fires when an action commits. The destructive primary only fires after the second tap; secondary actions fire on the first tap. |
| confirm | boolean | true | When true (default), the primary action requires a deliberate second tap within three seconds. Set false only for scripted demos. |
| disabled | boolean | false | Disables both controls. Use only when no platform is live — never to mask an error. |
| className | string | — | Forwarded to the root container. |
Types
SafetyActionKeyThe discrete action that fired. Your onAction handler dispatches on these. Resolved per scope — platform → e-stop + override, group → recall-group + pause, swarm → recall-swarm + suspend, mission → abort + pause.
type SafetyActionKey =
| "e-stop"
| "override"
| "recall-group"
| "recall-swarm"
| "abort"
| "pause"
| "suspend";Wiring
Wire onAction to your safety dispatcher. The consent gesture is internal — by the time your handler runs, the operator has confirmed.
<SafetyActions
scope="platform"
disabled={!hasLivePlatform}
onAction={(key) => {
switch (key) {
case "e-stop": return safetyAPI.estop(platformId);
case "override": return controlAPI.takeOver(platformId);
// ... your dispatcher
}
}}
/>Behavioural rules
Safety in one tap
The primary action is always visible and always in the first interaction layer. It is never collapsed into an overflow menu, never hidden behind a mode.
Deliberate transitions
The destructive action requires two deliberate taps within a 3-second window. The first arms, the second fires. Escape or the cancel chip disarm.
Accessibility
| Group role | Both buttons live inside a `role="group"` with an `aria-label` describing the scope (e.g. "Safety actions for platform"). |
|---|---|
| Armed state | The primary button toggles `aria-pressed` when armed. The `aria-label` updates to "Confirm <action>" so screen readers announce the confirmation step. |
| Keyboard | Enter or Space activates either button. Escape disarms the primary action while armed. Tab order: secondary → primary → cancel chip. |
| Focus | Both buttons carry visible focus rings using the accent ring colour. The danger ring is reserved for the armed state itself. |
| Disabled | The `disabled` prop sets `disabled` on both buttons and prevents the arm/fire flow. Use only when no platform is live — never to mask an error. |
JavaFX
Ships in the PRIZM JavaFX library for thick-client C3 apps as Rc3SafetyActions (extends HBox). Run the gallery to see it natively.
import design.prizm.fx.rc3.Rc3SafetyActions;
Rc3SafetyActions()
Rc3SafetyActions(Scope scope)| Member | Type | Default | Description |
|---|---|---|---|
| Scope | enum | — | PLATFORM / GROUP / SWARM / MISSION — determines the primary + secondary action set. |
| ActionKey | enum | — | The action that fired: E_STOP, OVERRIDE, RECALL_GROUP, RECALL_SWARM, ABORT, PAUSE, SUSPEND. |
| setScope | (Scope) → void | — | Rebuilds the surfaced actions for the scope. |
| setConfirm | (boolean) → void | true | Require the armed second tap on the primary action. Don't disable in production. |
| setOnAction | (Consumer<ActionKey>) → void | — | Fires when an action commits. |
The primary is always visible; the first tap arms it (CONFIRM · X, pulsing, ✕ cancel), a second tap within 3 s fires. ESCAPE / ✕ disarms; the secondary fires immediately. Danger uses the semantic tokens, never Ember. Reuses PrizmButton. Mirrors components/rc3/safety-actions.tsx.
Usage
Place safety actions where they remain visible whenever a platform is live — typically the top-right of the operator panel or the bottom of a control rail. Never collapse them into an overflow menu, never re-order them between surfaces, and never use the Ember signature colour for the primary destructive action: danger semantic stays distinct from identity.