Skip to main content
A confirmation view can be a single sandboxed widget instead of declarative blocks: every pixel of the card is yours. One thing is not negotiable — the confirm control is VoiceOS’s, a floating button the host renders over your card’s bottom-right corner. Your only lever on it is the label. That rule is structural, not stylistic: the widget sandbox has no approve message, so no markup you ship can trigger — or fake — an approval.

Declaring one

Validation enforces the shape:

The floating button

Bottom-right corner, no bar, no background — and deliberately self-contained: an almost-opaque dark pill with its own hairline and shadow, so it stays readable over anything you render, white or black. Three consequences for your layout:
  1. Keep roughly 150×44 px of the bottom-right visually quiet. Kit-built cards do this automatically (mode: "confirm" reserves the space); in hand-rolled HTML, leave the padding yourself.
  2. There is no Cancel button. Declining stays on the notch’s normal paths — saying “no”, or dismissing the card. Don’t draw your own cancel affordance; it wouldn’t do anything.
  3. The corner is cut for you. Confirmations render edge to edge and the surface rounds them, so anything you paint to the card’s own edge must use border-radius: var(--k-radius) — see The corner.

Per-invocation values: args

A confirmation is static manifest markup, but it confirms a specific call. The bridge solves this: a confirmation widget’s init message carries the pending tool-call arguments.
The kit’s runtime hydrates them into your markup: any element with data-voiceos-key="argName" (or built with vField) receives that argument’s value on load.

Letting the user edit

Inputs stage edits back through the bridge:
Keyed inputs rendered by the kit post this automatically as the user types. Staged edits ride the approval — your handler receives the edited values, exactly like a bound textField in a declarative card. Keys must name properties of the tool’s inputSchema; values are capped at 16 KB.
The declarative required gate doesn’t reach inside a widget, so the floating button won’t disable itself over an empty field you render. Validate in your handler and throw honestly if something essential is missing.

A worked example

The kit makes the whole thing a few lines — build the card at authoring time, paste the output into the manifest (the Studio does exactly this):
Pick one visual language per integration. If your tool results are custom widgets, make your confirmations custom widgets too — a branded result card next to a generic confirmation reads as broken.

Bridge reference

Every message, cap, and validation rule on the wire.