kai-choice
A “pick one of N” card — set the options in JavaScript, the user chooses one, and your app receives a typed kai-card action event.
- Shadow DOM
- Card-contract events
- Rich option rows
- Optional free-text escape (allowOther)
- Resolves to read-only after submit
Preview
Section titled “Preview”Set data in JavaScript (it’s an object) and listen for the kai-card CustomEvent:
<kai-choice id="ch" heading="Choose a plan"></kai-choice>
<script type="module"> import '@kitn.ai/ui/elements';
await customElements.whenDefined('kai-choice');
const el = document.getElementById('ch');
el.data = { prompt: 'Which plan fits your team?', options: [ { id: 'free', label: 'Free', meta: '$0' }, { id: 'pro', label: 'Pro', meta: '$12/seat', recommended: true }, { id: 'biz', label: 'Business', meta: '$29/seat' }, ], };
el.addEventListener('kai-card', (e) => { const ev = e.detail; // CardEvent if (ev.kind === 'action') console.log('chose:', ev.action, ev.payload); });</script>data— required fields per option:idandlabel. Optional:description,meta,recommended,media+imageAlt,disabled,payload.allowOtherappends an “Other…” row revealing an inline text input; submits asaction: '__other__'withpayload: { text }.- After submit the card renders read-only. Restore a resolved state on reload via
el.resolution = { kind: 'action', action: 'option-id' }.
Examples
Section titled “Examples”Plans with Pricing
Section titled “Plans with Pricing”Rows with Images
Section titled “Rows with Images”Quick Replies with Free-Text Escape
Section titled “Quick Replies with Free-Text Escape”allowOther appends an “Other…” row that reveals an inline text field when selected.
Resolved (Read-only)
Section titled “Resolved (Read-only)”Pre-render the post-submit view — useful for restoring persisted choices on reload.
Error State
Section titled “Error State”A malformed definition (empty options) triggers the inline error view and emits { kind: 'error' }.
| Property | Type | Default | Notes |
|---|---|---|---|
| theme | "light" | "dark" | "auto" | 'auto' | Color mode (`auto` follows prefers-color-scheme). |
| data | — | The choice definition (the CardEnvelope.data). Set as a JS PROPERTY: `el.data = { prompt, options:[…], allowOther?, submitLabel? }`. Import `ChoiceCardData` from `@kitn.ai/ui` for the full shape. | |
| cardId | string | — | Stable card id correlating every emitted CardEvent. Attribute: `card-id`. |
| heading | string | — | Heading rendered in the card chrome (= CardEnvelope.title). Attribute: `heading`. |
| resolution | Record<string, unknown> | — | Set when the user resolved this card; renders the read-only view. Property: `el.resolution = { kind:'action', action:'…' }`. |
| value | string | — | Controlled selection: the selected option id. When set, the consumer owns the current pick (RadioGroup `value`). Attribute: `value`. |
| defaultValue | string | — | Option id to pre-select on mount (uncontrolled seed). Attribute: `default-value`. |
| disabled | boolean | — | Disable the whole radiogroup + Submit (e.g. while the agent is busy). Attribute: `disabled`. |
Methods
Section titled “Methods”| Method | Signature | Notes |
|---|---|---|
| focus | (options?: FocusOptions): void | Focus the radiogroup roving tab stop (or the Other input when selected). |
| select | (optionId: string): void | Select an option by id locally: no emit, fires kai-value-change (same as a row click). Lets a consumer pre-highlight or drive selection externally. |
| send | (): void | Submit the current selection: emits the `action` verb on kai-card and resolves the card (single-shot). Named `send`, not `submit`, per the shared vocabulary. |
| dismiss | (): void | Trigger the dismiss path: emits `dismiss` on kai-card and optimistically collapses the card to its re-openable stub. |
| reopen | (): void | Re-open a dismissed card from its stub: emits `reopen` on kai-card. |
Composed from
Section titled “Composed from”This element wraps these SolidJS components — reach for them directly when you need finer control than the props expose.
ChoiceCard