Skip to content
kitn AI/UI

Form

kai-form

Lets an agent ask for structured input and validates it before sending it back.

  • Shadow DOM
  • JSON Schema driven
  • Client-side validation
  • Read-only resolved state
  • Card contract events

Assign the form definition in JavaScript — it’s an object, not an HTML attribute:

<kai-form id="my-form"></kai-form>
<script type="module">
import '@kitn.ai/ui/web-components';
await customElements.whenDefined('kai-form');
const form = document.querySelector('#my-form');
form.data = {
type: 'object',
title: 'How did we do?',
required: ['rating'],
'x-kai-submitLabel': 'Send feedback',
properties: {
rating: { type: 'integer', title: 'Overall rating', minimum: 1, maximum: 5, 'x-kai-widget': 'rating' },
comments: { type: 'string', title: 'Comments', 'x-kai-widget': 'textarea' },
},
};
form.addEventListener('kai-card', (e) => {
if (e.detail.kind === 'submit') console.log('submission data', e.detail.data);
if (e.detail.kind === 'action') console.log('secondary action', e.detail.action);
});
</script>
  • Schema → widgets is deterministic: string → text; string + enum → radio/select; integer + x-kai-widget: 'rating' → stars; boolean → switch; array → repeater/checkbox group; nested object → fieldset. The Every widget example shows the full mapping.
  • x-kai-* hints control field order (x-kai-order), submit label (x-kai-submitLabel), secondary buttons (x-kai-actions), placeholder (x-kai-placeholder), and dismissibility (x-kai-dismissible).
  • Field formats — x-kai-format, x-kai-mask, and x-kai-mask-guide mask a string field as the user types and decide its canonical submitted value. See Field formats & masks.
  • Events use the Card contract: kai-form fires no events of its own, only a bubbling kai-card CustomEvent. Relevant kinds: submit (detail.data is the validated object), action, ready, dismiss, and error.
  • resolution — set el.resolution = { kind: 'submit', data: { … } } to swap the form for a read-only <dl> summary.

Every schema-to-widget mapping in one form.

Required fields, minLength/maxLength, minimum/maximum, and format: 'email'; submit empty to see the inline errors.

Set el.resolution after a submission to render a read-only <dl> summary with a “Submitted” badge.

A non-object schema renders the inline error state and emits kai-card with kind: 'error'.

PropertyTypeDefaultNotes
theme'auto'Color mode (`auto` follows prefers-color-scheme).
data—The form definition: a JSON Schema + `x-kai-*` UI hints. JS property: `el.data = { type: 'object', properties: {...} }`.
cardId—Stable card id correlating every emitted CardEvent. Attribute: `card-id`.
heading—Heading rendered in the card chrome (= CardEnvelope.title). Attribute: `heading`.
resolution—Set when the user resolved this card; renders the read-only view. Property: `el.resolution = { kind:'submit', data:{…} }`.
values—Controlled field values (JS property). When set, it wins over local edits.
defaultValues—Initial values overlaying the schema defaults (uncontrolled seed; JS property).
disabledfalseDisable all fields + submit. Attribute: `disabled`.
MethodSignatureNotes
(options?: FocusOptions): voidFocus the first control, or the first INVALID control after a failed validation.
(): voidValidate + submit programmatically: focus the first invalid field on failure, else emit the `submit` CardEvent and resolve. Named `send`, not `submit`.
(): voidRun client-side validation now and return `{ valid, errors? }` WITHOUT submitting.
(): voidRe-seed the form from each field's `default` and clear errors.
(): voidTrigger the dismiss path (emit `dismiss` + collapse to the re-openable stub).
(): voidRe-open a dismissed card from its stub (emit `reopen`).

This element wraps these SolidJS components — reach for them directly when you need finer control than the props expose.

Form