Forms & inputs
Form
Composable, accessible form primitives and controls
detent-form
Port status
- Catalog status
- implemented
- Origin
- upstream
- Phase
- 3
- Wave
- phase-3-forms
- Group
- Forms & inputs
5.4 KB gzip for the class module
Variants
Recorded states
focus-visiblerecorded state; no settercheckedrecorded state; no setter
Usage
Import
import '/components/form/define.js';
// or register it yourself
import { DetentForm } from '/components/form/form.js';
Attributes
default-valuedescriptiondisablederrornamerequiredshow-password-toggletypevalue
Properties
erroronChangeonSubmit
Slots
labelleft-iconright-icon
Events
detent-change— { value: string }detent-submit— {}
Example
Runnable example: site/examples/form.ts. The snippet below is generated from the catalogued attributes.
<detent-form
default-value
description
disabled
error
name
required
show-password-toggle
type
value
></detent-form>
Property-only values
const element = document.querySelector('detent-form');
if (element !== null) {
// onSubmit: (e: FormEvent) => void
element.onSubmit = () => {};
// error: string | boolean
element.error = undefined;
}
Source
The pinned upstream source for this row:
src/components/ui/Form.tsxsha256 32b9aa0b5e4f…
Native files
The native module and its artifacts:
src/components/form/form.tssrc/components/form/styles.csssrc/components/form/define.tsdocs/components/form.mdsite/examples/form.tstests/browser/form.spec.tsevidence/components/form.md
API
Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.
Attributes
| Attribute | Property | Type | Default | Notes |
|---|---|---|---|---|
default-value | — | — | — | Recorded in the catalog as an attribute. |
description | — | — | — | Recorded in the catalog as an attribute. |
disabled | — | — | — | Recorded in the catalog as an attribute. |
error | error | string | boolean | undefined | Kebab-case attribute; camelCase property. |
name | — | — | — | Recorded in the catalog as an attribute. |
required | required | boolean | false | Presence semantics: present means true, absent means false. |
show-password-toggle | showPasswordToggle | boolean | false | Presence semantics: present means true, absent means false. |
type | — | — | — | Recorded in the catalog as an attribute. |
value | — | — | — | Recorded in the catalog as an attribute. |
Properties
| Property | Type | Default | Notes |
|---|---|---|---|
error | string | boolean | undefined | Property-only: assign from script; not accepted as an attribute. |
onChange | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
onSubmit | (e: FormEvent) => void | undefined | Property-only: assign from script; not accepted as an attribute. |
Events
| Event | Upstream prop | Payload type | Notes |
|---|---|---|---|
detent-change | onChange | (value: string) => void | Composed, bubbles; fires only for a user action. |
detent-submit | onSubmit | (event: FormEvent) => void | Composed, bubbles; fires only for a user action. |
Slots
| Slot | Notes |
|---|---|
label | Consumer content; rendered through a slot, never re-created. |
left-icon | Consumer content; rendered through a slot, never re-created. |
right-icon | Consumer content; rendered through a slot, never re-created. |
CSS customisation
- React `children`/`ReactNode` props become DOM slots; caller content stays light DOM.
- React callback props become typed composed CustomEvents; programmatic state assignment emits none.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- `lucide-react` icon components replaced with local SVG assets (ISC notice retained).
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- One `detent-form` tag implements the row's documented Input surface plus the Form root's submit relay; the twelve sibling exports (FormItem, FormLabel, FormControl, FormDescription, FormMessage, Textarea, Select, Checkbox, RadioGroup, RadioGroupItem, Switch) are not shipped, because PC-2.1 is one-to-one and the pinned source declares no variant enum to select among them.
- Native additions: type, name, value, default-value, required, disabled, setFormValue/setValidity, checkValidity/reportValidity, submit(), reset(), formDisabledCallback/formResetCallback/formStateRestoreCallback.
- `detent-submit` detail is `{}` and the event is cancelable: `preventDefault()` is honoured on the native submit, because a React FormEvent cannot become plain detail (PC-6.1/6.3/6.4).
- A shadow-DOM `<form>` cannot own light-DOM controls, so `detent-form` is a field inside the consumer's own `<form>` and relays its submission (PC-7.9); no noValidate wrapper is supplied.
- The password toggle is tabbable (upstream used tabIndex={-1}) and carries aria-pressed plus Show/Hide password names.
- The Framer Motion springSnappy entrance is CSS transitions (PC-10.4), removed under prefers-reduced-motion.
- Error and danger colours are token color-mix values, not the upstream dark-only rose-500/50.
What it does
A form container that validates its fields, focuses the first invalid control on submit and surfaces per-field errors.
Upstream behaviour
- Modular layout primitives: Form, FormItem, FormLabel, FormControl, FormDescription, FormMessage
- Comprehensive controls: Input, Textarea, Select, Checkbox, RadioGroup, Switch
- Spring-animated validation errors and password visibility toggle
- Tactile check, radio dot, and toggle switch spring physics
- Accessible ARIA semantics, required asterisks, and keyboard navigation
- Strict monochrome dark styling matching EasyUI surface elevation tokens
Differences from upstream
- React `children`/`ReactNode` props become DOM slots; caller content stays light DOM.
- React callback props become typed composed CustomEvents; programmatic state assignment emits none.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- `lucide-react` icon components replaced with local SVG assets (ISC notice retained).
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- One `detent-form` tag implements the row's documented Input surface plus the Form root's submit relay; the twelve sibling exports (FormItem, FormLabel, FormControl, FormDescription, FormMessage, Textarea, Select, Checkbox, RadioGroup, RadioGroupItem, Switch) are not shipped, because PC-2.1 is one-to-one and the pinned source declares no variant enum to select among them.
- Native additions: type, name, value, default-value, required, disabled, setFormValue/setValidity, checkValidity/reportValidity, submit(), reset(), formDisabledCallback/formResetCallback/formStateRestoreCallback.
- `detent-submit` detail is `{}` and the event is cancelable: `preventDefault()` is honoured on the native submit, because a React FormEvent cannot become plain detail (PC-6.1/6.3/6.4).
- A shadow-DOM `<form>` cannot own light-DOM controls, so `detent-form` is a field inside the consumer's own `<form>` and relays its submission (PC-7.9); no noValidate wrapper is supplied.
- The password toggle is tabbable (upstream used tabIndex={-1}) and carries aria-pressed plus Show/Hide password names.
- The Framer Motion springSnappy entrance is CSS transitions (PC-10.4), removed under prefers-reduced-motion.
- Error and danger colours are token color-mix values, not the upstream dark-only rose-500/50.