A Field owns everything around one value: the visible name, help text, errors and the dirty, touched and invalid state. Put one control inside it, such as an Input, Text area, Select, Checkbox or Switch, and the Field labels it and connects descriptions and errors for assistive technology.
Validation
Native constraints on the control (required, type, minlength, pattern) validate through the Field. validation-mode decides when: on-submit (the default without a Form), on-blur or on-change. Type an invalid address and leave the input to see the error.
Validate on blur
Default density
Compact density
Restart from the initial state
Show the copyable source
For server results or your own checks, set error with invalid. A validator property receives the value and every named value in the same form, and may return a promise.
Duplicate names preserve ordered values, including nested list values; unnamed Fields are omitted. Explicit/server errors, custom validation and native constraints remain distinct lanes.
Submission touches fields and prevents synchronous invalid submission. Async validation does not retroactively cancel native submission; cancel the submit event explicitly when awaiting async outcomes is required. Failed on-submit validation revalidates later edits.
Custom validator
Default density
Compact density
Restart from the initial state
Show the copyable source
orientation="horizontal" puts the label beside the control. Compact binary controls such as Switch and Checkbox move to the end of the row with the label and description stacked beside them, which is the usual settings layout.
Horizontal
Default density
Compact density
Restart from the initial state
Show the copyable source
<div style="display:grid;gap:var(--tp-space-6);max-inline-size:28rem">
<tp-field label="Marketing emails" description="Product news and tips, about once a month." orientation="horizontal">
<tp-switch name="marketing"></tp-switch>
</tp-field>
<tp-field label="Two-factor authentication" description="Require a code from your authenticator app at sign-in." orientation="horizontal">
<tp-switch name="mfa" default-checked></tp-switch>
</tp-field>
</div>
orientation="responsive" switches between the stacked and horizontal layouts based on the Field’s own container width. Only responsive orientation establishes size containment and fills its available container.
Rich content
The label, description and error slots take precedence over the attributes of the same name. Use them for a link or emphasis the plain-text attributes can’t carry.
Slots
Default density
Compact density
Restart from the initial state
Show the copyable source
<tp-field style="max-inline-size:22rem">
<span slot="label">API key <span style="color:var(--tp-muted-foreground);font-weight:normal">(optional)</span></span>
<tp-input name="api-key" placeholder="sk_live_…"></tp-input>
<span slot="description">Find it in <a href="#rich-content" style="color:inherit">Developer settings</a>.</span>
</tp-field>
Groups of fields
A Field renders a native fieldset. Give it a legend and put peer Fields in its group slot, here inside one wrapper that sets their spacing, to caption a section of a form, such as an address. legend-scale="field" sizes the caption like a field label instead of a section heading. To join the editors of one value into a single row, use Field group instead.
Legend and group
Default density
Compact density
Restart from the initial state
Show the copyable source
disabled on the Field disables its control and dims the label and description together, so the whole row reads as unavailable.
Disabled
Default density
Compact density
Restart from the initial state
Show the copyable source
<tp-field label="Plan" description="Contact your admin to change plans." disabled style="max-inline-size:22rem">
<tp-input name="plan" default-value="Business"></tp-input>
</tp-field>
Custom controls
A custom element joins a Field when it carries data-field-control. A TpFormElement subclass receives the Field context (disabled, name, invalid, state markers and the autofill opt-out) through setFieldContext(), and the Field’s label, description and error through setFieldAssociation(). A Label’s text arrives the same way.
After each update the element writes aria-label, aria-describedby, aria-errormessage and aria-invalid on the element that associationTarget() returns. It keeps the description and error text as hidden nodes beside that element and restores the values it replaced once the association changes or the element disconnects.
A control whose labelled element it cannot write directly overrides applyFieldAssociation(attributes). It receives a FieldAssociationAttributes record with the four values, each a string or null: the Field label (else the host’s aria-label), the description and error node ids, the error node id, and 'true' while invalid. The hook runs after every update with the current values, also when none of them changed, so an override must be idempotent: applying the same record again must leave the element as it was. Returning true means the control applied them itself: the element then writes nothing to associationTarget(), and the description and error text stay in the control’s shadow root even when associationTarget() returns null. The hook is not called on disconnect, and a control that rebuilds its labelled element applies the last values again.
The description and error text sit in the node that the protected associationContainer() returns, which is the render root by default; a control whose labelled element lives inside one part of its shadow root can return that part instead, as long as it stays in the same tree.
<tp-field label="Trail map" description="Draw the route you plan to take">
<sketch-pad name="route"></sketch-pad>
</tp-field>
API Reference
Every element also accepts motion-policy.
Attributes
AttributePropertyTypeDefaultDescriptionnamenamestring''The form name of the value; takes precedence over the control's own name without overwriting
it.labellabelstring''The visible name of the control, rendered as a Label that focuses it.descriptiondescriptionstring''Help text below the control, announced with it.errorerrorstring''An error message from your own checks or the server; shown while the Field is invalid.legendlegendstring''The caption of a group of Fields in the group slot; the Field then renders as a native
fieldset.legend-scalelegendScale'section' | 'field''section'Sizes the legend as a section heading or as a field label.native-labelnativeLabelbooleantrueWhether a click on the label activates the control; turn it off for a control that opens a
popup, so one click does not open it twice.no-autofillnoAutofillbooleanfalseOpts the Field's text-entry control out of host and extension autofill.validation-modevalidationModeFieldValidationMode | undefined—When the Field validates: on submit, when the control loses focus, or on every change. Without
it the Field follows its Form, else validates on submit.validation-debouncevalidationDebouncenumber0Milliseconds to wait after a change before validating in on-change mode.dirtydirtyboolean | undefined—Overrides whether the value counts as changed from its initial value; leave unset to let the
Field track it.touchedtouchedboolean | undefined—Overrides whether the control counts as visited; leave unset to let the Field track it.titletitlestring''The name of a grouped choice, such as a set of Checkboxes or a Radio group, shown above its
options.
Properties
PropertyTypeDefaultDescriptionerrorsFieldError[][]Several error messages at once, as strings or { message } records; duplicates are dropped and
the rest render as a list.errorMatchboolean | keyof ValidityState | undefined—Which failures show the error: false hides it, true always shows authored messages, and a
validity key such as valueMissing shows it only for that constraint.validatorFieldValidator | undefined—Your own check: receives the value and every named value in the same form, and returns an error
message, a list of them, nothing, or a promise of one of these.validityContent((state: FieldValidity) => unknown) | undefined—Renders extra content below the control from the current validity state, such as a strength
meter.actionsread-onlyobject{ validate: () => this.validate() }The Field's actions as plain functions, for passing validate to code that holds no reference
to the element.effectiveDisabledread-onlyboolean—Whether the Field is disabled, by itself or by the grouping Field around it.fieldSetread-onlyboolean—Whether the Field captions a group of Fields rather than owning a control.controlread-onlyFieldControl | null—The control the Field registered, or null while it has none.valueread-onlyunknown—The current value of the registered control: its text, checked or pressed state, or selection.effectiveNameread-onlystring—The name the value submits under: the Field's name, else the control's.validationRunread-onlyValidationRun | null—The newest validation run, with its status and completion promise.validityStateread-onlyFieldValidity—A snapshot of the Field's state: value, initial value, errors, native validity flags, and
whether it is dirty, touched, filled, focused or pending.moderead-onlyFieldValidationMode—The validation trigger in effect, after following the Form when validationMode is unset.
Events
EventTypeDescriptiontp-validationCustomEvent<{ run: ValidationRun; state: FieldValidity; }>After a validation run settles; detail.run is the run and detail.state the Field's validity state.tp-presence-completeCustomEvent<{ present: boolean; }>After the error finishes appearing or disappearing; detail.present says which.
Methods
MethodReturnsDescription[fieldSubmission]()ValidationRunValidates as part of a submission, marking the Field touched first; the enclosing Form calls
it.validate()ValidationRunValidates now and returns the run; a newer run supersedes this one, and a promise from the
validator leaves the Field pending until it settles.
Slots
SlotDescriptiondefaultThe control, directly or inside a layout wrapper.controlThe control, when it sits beside other default content.itemA wrapper around one member of a grouped choice; its disabled state scopes that member.labelRich label content; takes precedence over label.titleRich name of a grouped choice; takes precedence over title.descriptionRich help text; takes precedence over description.errorRich error content, shown while the Field is invalid; takes precedence over the error messages.legendRich caption of a group of Fields; takes precedence over legend.groupPeer Fields captioned by the legend, usually inside one layout wrapper.separatorA caption centered over a dividing line below the Field.
CSS parts
PartDescription::part(field)The root fieldset that holds the legend, the Field's own row and the separator.::part(field-control-region)The column that holds the control, its description and its error.::part(field-description)The help text below the control.::part(field-error)The error message, shown while the Field is invalid and announced as an alert.::part(field-field)The row of the label and the control region; beside a Switch or Checkbox it lays out as a choice row.::part(field-field-group)The region that holds the group slot and the Field's own row.::part(field-label)The Label that names the control, from label or the label slot.::part(field-legend)The caption of a group of Fields, from legend or the legend slot.::part(field-separator)The dividing line below the Field, with its centered caption.::part(field-title)The name of a grouped choice, from title or the title slot.
Related
Components, widgets and patterns that use this one.