kit-field
<kit-field label="Email" description="We'll never share it." required> <input type="email" name="email" /></kit-field><kit-field> provides label + description + error UI for a form control. The control itself is a real native input/textarea/select that you slot in. The field wires up aria-describedby, aria-invalid, the visible required marker, and id/for plumbing.
Package
Section titled “Package”@atheory-ai/kitsune-ui
import '@atheory-ai/kitsune-ui'import { KitFieldElement } from '@atheory-ai/kitsune-ui'Attributes / properties
Section titled “Attributes / properties”| Attribute | Type | Default | Notes |
|---|---|---|---|
label | string | — | Visible label text. |
description | string | — | Optional help text below the control. |
error | string | — | Optional error text. When set, the control gets aria-invalid="true" and aria-describedby points at the error. |
required | boolean | false | Visual asterisk and required propagated to the slotted control. Reflects. |
invalid | boolean | derived | Reflects when error is non-empty. Style with [invalid]. |
field-id | string | auto-generated | The id used to wire up label/description/error if the slotted control has no id. |
| Slot | Purpose |
|---|---|
| (default) | The form control: <input>, <textarea>, or <select>. |
The control stays in the light DOM so it participates in <form> natively.
Examples
Section titled “Examples”Required input
Section titled “Required input”<kit-field label="Title" required> <input name="title" autocomplete="off" /></kit-field>With description
Section titled “With description”<kit-field label="Email" description="We'll send a verification link."> <input type="email" name="email" /></kit-field>With error
Section titled “With error”<kit-field label="Title" error="Title is required"> <input name="title" /></kit-field>The error renders below the control with role="alert" and the input gets aria-invalid="true" and aria-describedby="<id>-error".
With a textarea or select
Section titled “With a textarea or select”<kit-field label="Body"> <textarea name="body" rows="6"></textarea></kit-field>
<kit-field label="Tone"> <select name="tone"> <option>Casual</option> <option>Formal</option> </select></kit-field>Same wiring works for any standard form control.
CSS custom properties
Section titled “CSS custom properties”| Property | Default |
|---|---|
--kit-space-1 | 0.25rem (label↔control gap) |
--kit-space-2 | 0.5rem (control padding) |
--kit-space-3 | 0.75rem |
--kit-color-surface | Canvas (control background) |
--kit-color-border | CanvasText |
--kit-color-text | CanvasText |
--kit-color-muted | GrayText (description) |
--kit-color-error | oklch(58% 0.18 25) |
--kit-radius-sm | 0.375rem |
--kit-focus-ring | Highlight |
Form participation
Section titled “Form participation”The slotted control is a real native control. new FormData(form) reads it. form.requestSubmit() validates it. Constraint validation (required, minlength, pattern, type) all work as the platform defines.
form.addEventListener('submit', (e) => { e.preventDefault() const data = Object.fromEntries(new FormData(form).entries()) // ...})Updating errors dynamically
Section titled “Updating errors dynamically”const field = document.querySelector('kit-field')!field.error = 'Title is too long'// laterfield.error = ''When error changes, the field updates the description-binding, sets aria-invalid, and reflects the invalid host attribute for styling.
Accessibility notes
Section titled “Accessibility notes”- The label is a real
<label>withforpointing to the slotted control’sid. - If the slotted control has no
id, kit-field assigns one automatically. aria-describedbypoints at the description (when only description is present), or at the error (when error is present), or at both (you can override witharia-describedbyon the input).- Errors render with
role="alert"so screen readers announce them on appearance.
Limitations (today)
Section titled “Limitations (today)”- Only supports a single slotted control per field.
- Doesn’t yet expose all native validation messages (e.g.,
:invalidstyling responds, butvalidationMessageisn’t shown unless you seterrormanually).
A future iteration will be a fully form-associated custom element with first-class constraint validation. For now, real <input> inside a slot covers the common case.