Skip to content

Form ​

An enhanced native <form> supporting validation and submission of inner fields according to rules.

Cross-shadow submit entry: oas-form wraps a native <form> inside its shadow root, so buttons in the light DOM (including oas-button) do not have native submit semantics. Call the component's public submit() method at submit time (e.g. this.closest('oas-form').submit()); it delegates to the inner form's requestSubmit(), preserving submit-event semantics and triggering the same validation flow that dispatches oas-submit / oas-validate-fail — do not reach into shadowRoot.querySelector('form') to drive the inner form.

The data source is each field's value attribute (controlled mode). Fields validated by the form are oas-input / oas-textarea / oas-select / oas-auto-complete / oas-cascader / oas-tree-select / oas-input-number / oas-radio / oas-radio-group / oas-date-picker / oas-slider / oas-rate / oas-pin-input / oas-dynamic-tags / oas-combobox / oas-picker / oas-transfer (model-value channel) / oas-dynamic-input (model-value channel) / oas-checkbox / oas-switch (checked channel) with a name. oas-form has a built-in listener for oas-input / oas-change events bubbling from inner fields and automatically writes back to that field's value attribute (null becomes an empty string) — no per-field wiring needed.

Feature Demo ​

The feature demo area only demonstrates field collection and submission, without validation rules.

Basic Usage ​

Collect & submit

Submit

Without rules, submission performs no validation and dispatches oas-submit directly, with detail.values carrying the collected results of all fields with a name.

Mixed Controls ​

Mixed controls

Submit

Nested name paths: nested values ​

Field name supports dot-path syntax: numeric segments are array indices, other segments are object keys — profile.city assembles into { profile: { city } }; users.0.name and users[0].name are equivalent spellings that assemble into { users: [{ name }] }. On submit, oas-submit's detail.values is the nested structure; rules keys match by the full path string (e.g. "users.0.name"); initial-values writes in through the same nested paths and reset() restores them. Plain names without path syntax assemble exactly as before.

Nested name path submit

Submit

After submitting, values looks like {"name":"Alex","profile":{"city":"Hangzhou"}} — the path segments define the structure.

Dynamic field group form-list ​

oas-form-list maintains an add/remove group of field rows inside the form: put a <template> inside the component as the row template; cloned row fields get their name indexed automatically — either use the {index} placeholder in the template (name="users.{index}.name"), or set name="users" on the component and write bare names in the template (auto-prefixed to users.N.field). min / max constrain the row count (rows are padded up to min; lowering min never removes existing rows, and an invalid max is treated as unlimited), each row has a remove button, and after removal the remaining rows are renumbered with their filled values kept. Fields stay in the light DOM, so validation / submit / oas-values-change all follow the host form; the component dispatches oas-add / oas-remove (detail: { index }).

Dynamic field group form-list

Submit

After submitting, values looks like {"members":[{"name":"Alex","role":"self"},{"name":"Sam","role":"relative"}]}; in plain HTML write the row template as a literal <template>, while in md/Vue compiled contexts prefer injecting an HTMLTemplateElement built in JS (template content pass-through is unreliable under template compilation).

Native Form Integration (form-associated) ​

Fifteen common form components are form-associated custom elements (formAssociated: true): they work directly inside a native <form> — <label for> association works (clicking the label focuses/activates the control, screen readers announce the label text), values are collected via standard FormData (submitted only when name is set), form.reset() restores initial values, fieldset[disabled] disables them, and required joins the native validation chain (checkValidity() / :invalid pseudo-class).

native form + label for + FormData + reset

Read FormDataform.reset()

Supported (15 components): input / textarea / input-number / checkbox / radio / radio-group / switch / select / combobox / auto-complete / tree-select / mentions / date-picker / time-picker / upload. Value semantics follow the native ones: multiple mode (select / tree-select / date-picker multiple) submits same-name entries; date / time range mode submits name-start / name-end; upload submits File; unchecked checkables submit nothing. Works in parallel with oas-form's collectFields mechanism.

Validation ​

The validation area demonstrates rules-declared validation rules and failure feedback.

Validation rules: { required, message, minLength, maxLength, pattern, validator, validateTrigger } (validator is a custom validation function; functions are not JSON-serializable, use the rules property channel; validateTrigger overrides the form-level trigger per field). On failure, the field is marked aria-invalid (red-bordered input), an error message is shown in red below the field, and oas-validate-fail is dispatched.

Required & Format Validation ​

Required & format validation

Submit

Length Validation ​

minLength validation

Submit

Disabled Fields Skip Validation ​

Disabled fields are not validated

Submit

Submit & Validation-fail Events ​

submit / validate-fail

Submit

Grid Form Layout ​

With layout="grid", the form element becomes a 24-column grid and oas-form-item spans columns via span (default 24 = full row); gap controls grid spacing, label-align positions the label (left / right / top, default top), and label-width sets the label column width for left/right. On validation failure, error messages are collected into the oas-form-item error slot (role="alert").

Two-Column Grid with Validation ​

Two-column grid layout

Submit

label-align & label-width ​

Switch label-align

Inline Form Layout ​

With inline, items are laid out horizontally: the label sits on the left of the control (auto-width), controls size to their content, item spacing follows gap (default var(--oas-space-4)), and items wrap when the container is too narrow. Coexists with layout and takes precedence over it; forces label-align to left and label-width to auto. Suited to compact toolbars like login and search.

Inline Login Form ​

Inline login form

Log in

Inline Search Form ​

Inline search form

Search

Controlled syncing and event listeners (wired in one <script> block):

Form-Level Capabilities ​

Whole-Form Disabled ​

The disabled attribute aligns with the config-provider global-disable semantics: all fields are disabled through their own form-associated disable channel (inner controls disabled, interaction blocked), without writing back the field's disabled attribute (fields fully recover when released); while the form is disabled, submission skips all validation.

Whole-form disabled

Submit (skips validation while disabled)
Disable the form

Initial Values & Reset ​

initial-values are written into the corresponding fields after mount (input via value, switch via checked, transfer/dynamic-input via model-value); reset() restores the initial values and clears validation error states without dispatching any events (consistent with the native form reset baseline). The initialValues property channel is also supported (property takes precedence over attribute).

initial-values and reset

SubmitReset

Custom Validation Function (validator) ​

validator runs after the built-in checks of its rule: return true to pass, a string as the error message, or a Promise for async validation. Functions are not JSON-serializable, so set them through the rules property channel (form.rules = {...} in script).

Custom validation function

Submit

Validation Trigger (validate-trigger) ​

validate-trigger controls when per-field live validation runs: input (default, validate as you type) / blur / change; a rule's validateTrigger overrides the form level. Submission always validates everything. The default live-on-input validation settles errors before the user clicks submit, so an error appearing/disappearing at click time can never shift a control out from under the pointer and swallow the click. Once a field has an error, every subsequent keystroke re-validates it live (clearing as soon as it is corrected). The example below uses blur: type an invalid phone number, then click elsewhere (blur) to see the red error text; fix it and blur again to clear it.

Validate on blur

Scroll to First Error (scroll-to-first-error) ​

With scroll-to-first-error set, a failed submit focuses the first invalid field and smooth-scrolls it into view (degrades to an instant jump when the system prefers reduced motion). The long form below scrolls — the remark field sits at the very bottom; click submit and watch the container scroll down.

Scroll to first error

Submit (scrolls to first error)

Values Change Event (oas-values-change) ​

Dispatched whenever any field value changes, detail: { name, value, values } (values is a snapshot of all current values). Initial-value writes and reset() are silent channels and do not dispatch.

oas-values-change

Script wiring (controlled sync + event feedback for each demo):

Form-Level Size & Label Colon (size / colon) ​

size distributes the form-level size tier (small / medium / large) to field controls inside the form. Priority: a field's own explicit size > the form-level size > config-provider global injection > the default tier (when both form-level and global injection are present, the form-level wins). colon renders a colon after the label of every oas-form-item in the form. Click the buttons below to watch fields resize and the colon toggle live.

Form-level size + colon

Checkbox follows the form-level sizeOwn size=medium wins (ignores form level)Switch to smallSwitch to largeToggle colon

Help Text & Status Icon (help / status-icon) ​

help renders persistent helper text below the control, independent of validation errors. With status-icon on a form-item, a danger status icon appears before the error text when validation fails (hidden again once the error clears).

help + status-icon

Submit

Custom Validation Messages (validate-messages) ​

validateMessages (property channel, recommended) or validate-messages (JSON attribute) overrides locale-default messages per rule type. Templates support ${min} / ${max} / ${value} placeholders; an explicit rule.message has the highest priority.

validate-messages

Submit

API ​

Methods ​

MethodDescription
submit()Public submit entry: delegates to the inner form's requestSubmit() (preserves the submit event and submitter semantics); after validation dispatches oas-submit / oas-validate-fail. Across the shadow boundary light-DOM buttons have no native submit semantics, so use this method uniformly (e.g. this.closest('oas-form').submit())
validate()Public validation entry: validates all fields and syncs error states (aria-invalid + error text), returns Promise<boolean>. Pure validation — dispatches no oas-submit / oas-validate-fail and performs no scroll-to-first-error; intended for external gating consumers such as step containers (awaits async validators, skips disabled fields, passes by default with no rules)
getValues()Public value entry: a snapshot of all current field values (nested structure), same shape as the detail.values dispatched by submit() — no validation, disabled fields not filtered out; zero-interaction fields prefilled via the value attribute are included. Returns Record<string, unknown>

oas-form ​

Attributes ​

AttributeDescriptionTypeDefault
colonRenders a colon after every form-item label in the form (CSS ::after, no DOM text)——
disabledWhole-form disable: fields are disabled via their form-associated channel (no write-back of the disabled attribute); submission skips validation while disabledboolean—
gapSpacing (grid gap in grid mode; item spacing in inline mode), token value e.g. var(--oas-space-4); 0 by default in grid, var(--oas-space-4) by default in inlinestring0
initial-valuesInitial values JSON (the initialValues property takes precedence): written into fields after mount; reset() restores themRecord<string, unknown> | string—
inlineInline layout: items laid out horizontally (label on the left of the control, controls auto-width, wraps to new lines); item spacing follows gap (default var(--oas-space-4)); coexists with layout and takes precedence over it; forces label-align to left and label-width to autoboolean—
label-alignLabel alignment: left / right / top (default top in grid mode; forced to left in inline mode)stringtop
label-widthLabel column width when label-align is left/right (ignored in inline mode, auto)——
layoutLayout mode: vertical (default, stacked) / grid (24-column grid); non-enum values fall back to vertical; inline attribute takes precedence when presentstringvertical
rulesValidation rules JSON: { fieldName: [{ required, message, minLength, maxLength, pattern }] }Rules | string—
scroll-to-first-errorOn validation failure, focus the first invalid field and smooth-scroll it into view (instant jump under prefers-reduced-motion)boolean—
sizeForm-level size tier distributed to all fields via the data-form-size channel (a field's own explicit size wins; form-associated fields follow dynamically)——
validate-messagesOverrides locale-default validation messages per rule type (property/JSON channels, ${min}/${max}/${value} placeholders, default fallback)ValidateMessages | string—
validate-triggerWhen per-field live validation fires: input (default, validate as you type) / blur / change; a rule's validateTrigger overrides per field; submission always validates everythingstringinput

Events ​

EventDescription
oas-submitValidation passed, detail: { values }
oas-validate-failValidation failed, detail: { errors, values }
oas-values-changeDispatched when any field value changes, detail: { name, value, values } (values is a whole-form snapshot; initial-value writes and reset() are silent)

Slots ​

NameDescription
defaultForm content (oas-form-item and friends)

oas-form-item ​

Attributes ​

AttributeDescriptionTypeDefault
helpPersistent helper text below the control, independent of validation errorsstring—
labelLabel text (no label row when omitted)string—
nameField name (validation association)——
requiredRequired asterisk (visual only; validation is still driven by form rules)boolean—
spanColumns spanned in the 24-column grid (only when form layout="grid"; non-integer in 1-24 → 24)string24
status-iconShows a danger status icon before the error text while the error is presentboolean—

Slots ​

NameDescription
defaultField control

CSS Variables ​

CSS VariableDefault
--oas-form-label-width96px

On validation failure, failed fields are marked aria-invalid; error messages can be retrieved via form.getErrors(). For fields wrapped in oas-form-item, the error text is collected into the form-item's error slot (role="alert").

Released under the MIT OR Apache-2.0 License.