
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@lit-labs/forms
Advanced tools
A library for building form-associated custom elements with Lit.
[!WARNING]
This package is part of Lit Labs. It is published in order to get feedback on the design and may receive breaking changes or stop being supported.
Please read our Lit Labs documentation before using this library in production.
From inside your project folder, run:
$ npm install @lit-labs/forms
Form-associated custom elements are web components that participate in form
submission, validation, and state restoration, just like built-in form elements.
@lit-labs/forms helps builds correct form-associated custom elements by
setting the proper ARIA roles, form value, disabled state, and more.
This package provides:
FormControl: A class mixin that makes it easy to build
form associated custom elements that implement the standard form control APIs.FormAssociated: A lower-level class mixin that only
helps with form association, but doesn't add any public APIs.FormControl mixinThe FormControl mixin adds standard form-related public API properties and
methods to a custom element. It also enables the use of decorators that let
developers easily bind class fields to the form value and manage form state for
restoration.
[!NOTE]
FormControlextends theFormAssociatedmixin, which handles the ElementInternals integration and enables the decorators, but doesn't add any public API to the class.It's recommended that most developers use
FormControlinstead ofFormAssociatedin order to add the idiomatic API that users expect from form controls (like.disabled,.form,.checkValidity(), etc.). UseFormAssociatedonly if you need to implement a completely custom API surface.
import {LitElement, html} from 'lit';
import {customElement} from 'lit/decorators.js';
import {FormControl, formValue} from '@lit-labs/forms';
@customElement('simple-input')
export class SimpleInput extends FormControl(LitElement) {
@formValue()
accessor value = '';
override render() {
return html`
<input
.value=${this.value}
@input=${(e: Event) =>
(this.value = (e.target as HTMLInputElement).value)}
/>
`;
}
}
The added fields and methods mimic native form controls, providing a familiar API:
form: a readonly property that returns the associated form element.labels: a readonly property that returns the labels associated with the
element.name: a read/write property that reflects the name attribute.disabled: a read/write property that reflects the disabled attribute.validity: a readonly property that returns the ValidityState of the
element.validationMessage: a readonly property that returns the error message that
would be shown to the user if the element was to be checked for validity.willValidate: a readonly property that returns true if internals' target
element will be validated when the form is submitted. For example, disabled or
hidden elements are not validated.checkValidity(): If the element is invalid, returns false and fires an
invalid event.reportValidity(): Like checkValidity() but also shows the validation
message to the user.FormAssociated mixinThe FormAssociated mixin helps define a form-associated custom element.
FormAssociated creates a new form-associated base class and implements a
number of best-practice behaviors for form-associated elements:
internals.role.internals.setFormState().formResetCallback().formStateRestoreCallback().internals.ariaDisabled via
formDisabledCallback()._getValidity(), when the form
value changes and updates internals.setValidity() with the result.FormAssociated doesn't add any public API to the element. Its behavior can be
controlled with the decorators described below.
@formValue()The form value can be stored in any class field decorated with @formValue.
@formValue()
accessor value = '';
By default, the field must be of type string | File | FormData | null.
If your element has a value of a different type, you can use a custom form value
converter:
@formValue({
converter: {
toFormValue(value: number) {
return String(value);
},
fromFormValue(value: string) {
return Number(value);
},
},
})
accessor value = 23;
@formStateGetter(), @formStateSetter(), and @formState()Form state is additional data stored by the browser alongside the form value. While the form value is what gets submitted to the server, the form state is used to restore the element's user interface when the user navigates back or forward, or when the browser restores a session.
The underlying browser API is ElementInternals.setFormValue(value, state). The
FormAssociated mixin automatically calls this method whenever the @formValue
property changes. If you provide form state, it is passed as the second
argument.
When the browser restores the element, FormAssociated receives the stored
state and uses it to reset the element's properties.
To provide this state, you can use the @formState decorator on a property, or
@formStateGetter and @formStateSetter on methods.
The @formState() decorator marks a field as being part of the form state. Its
value will be included in the state passed to internals.setFormValue().
@formStateGetter() and @formStateSetter() allow for more complex state
handling. They are applied to methods called to get or set the form state. The
@formStateGetter() decorated method is called to retrieve the state object to
pass to internals.setFormValue(). The @formStateSetter() decorated method is
called with the restored state object when the browser restores the element.
class CustomStateElement extends FormAssociated(LitElement) {
@formValue()
accessor value = 'bar';
@formState()
@property()
accessor count = 0;
@formStateGetter()
// @ts-expect-error #getFormState is called dynamically
#getFormState() {
return this.value + '#' + this.count;
}
@formStateSetter()
// @ts-expect-error #setFormState is called dynamically
#setFormState(state: string) {
const [value, count] = state.split('#');
this.value = value;
this.count = Number(count);
}
}
[!WARNING]
TypeScript will complain that a private getter isn't called even if it's decorated and called by the decorator. The FormAssociated API might change so that it doesn't require a
@ts-expect-errorcomment to suppress this warning.
isDisabled(): An element can be disabled because its ancestor fieldset is
disabled, so checking the disabled attribute is insufficient. isDisabled()
checks if the element matches :disabled, correctly handling inherited
disabled state.
import {isDisabled} from '@lit-labs/forms';
Please see CONTRIBUTING.md.
FAQs
Form helpers for Lit
The npm package @lit-labs/forms receives a total of 16 weekly downloads. As such, @lit-labs/forms popularity was classified as not popular.
We found that @lit-labs/forms demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 11 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.