Form
kai-form
Point a JSON Schema at <kai-form> and get a fully themed, accessible, client-validated form — labels, widgets, submit button, and a read-only resolved state — without writing a single input element.
- Shadow DOM
- JSON Schema driven
- Client-side validation
- Read-only resolved state
- Card contract events
Preview
Section titled “Preview”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/elements';
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 deterministically:
string→ text;string + enum→ radio/select;integer + x-kai-widget: 'rating'→ stars;boolean→ switch;array→ repeater/checkbox group; nestedobject→ fieldset. See the Every widget example for the full mapping. x-kai-*hints in the schema 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).- Events use the Card contract —
kai-formfires no events of its own; it emits a single bubblingkai-cardCustomEvent. Relevant kinds:submit(detail.datais the validated object),action,ready,dismiss, anderror. resolution— setel.resolution = { kind: 'submit', data: { … } }to swap the form for a read-only<dl>summary.
Examples
Section titled “Examples”Feedback Form
Section titled “Feedback Form”Star rating, free-text textarea, enum radio group, boolean switch, and a secondary Skip action.
Every Widget
Section titled “Every Widget”Exercises the full schema-to-widget mapping: text, email, URL, date, password, select, number, slider, rating, switch, checkbox, tag list, checkbox group, repeater, and nested fieldset.
Validation
Section titled “Validation”Required fields, minLength/maxLength, minimum/maximum, and format: 'email' — submit empty to see inline errors.
Resolved (Read-only)
Section titled “Resolved (Read-only)”After a successful submission, set el.resolution to render a read-only <dl> summary with a “Submitted” badge.
Invalid Envelope
Section titled “Invalid Envelope”Pass a non-object schema to see the inline error state; the element also emits kai-card with kind: 'error'.
| Property | Type | Default | Notes |
|---|---|---|---|
| data | Record<string, unknown> | — | The form definition — a JSON Schema (`type:'object'`) + `x-kai-*` UI hints (the CardEnvelope.data). Set as a JS PROPERTY: `el.data = { type:'object', properties:{…} }`. Import the `FormDefinition` type from `@kitn.ai/ui` for the full shape (it is self-referential, so the element types it loosely). |
| 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:'submit', data:{…} }`. |
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.