Form-associated custom elements (FAE) — это расширение возможностей стандартных веб-компонентов, позволяющее интегрировать пользовательские элементы с HTML-формами. В контексте Stencil это особенно актуально, так как фреймворк предоставляет мощный механизм для создания изолированных, реактивных компонентов с декларативной разметкой.
Form-associated custom elements позволяют компоненту
вести себя как стандартный <input>,
<select> или <textarea>. Это
означает, что пользовательский элемент может:
formData;disabled,
required, name;form.reset(),
form.submit()).Для активации поведения FAE элемент должен быть создан с
использованием свойства formAssociated: true в конструкторе
компонента.
export class MyCustomInput extends HTMLElement {
static formAssociated = true;
}
Stencil позволяет создавать FAE через использование декоратора
@Component и стандартного API веб-компонентов. Основные
шаги:
import { Component, Prop, h, Element, State } from '@stencil/core';
@Component({
tag: 'my-custom-input',
styleUrl: 'my-custom-input.css',
shadow: true
})
export class MyCustomInput {
@Element() el!: HTMLElement;
@Prop() name!: string;
@Prop({ mutable: true }) value: string = '';
@Prop() required: boolean = false;
private internals!: ElementInternals;
componentWillLoad() {
this.internals = (this.el as any).attachInternals();
}
handleInput(event: Event) {
const input = event.target as HTMLInputElement;
this.value = input.value;
this.internals.setFormValue(this.value);
}
render() {
return <input type="text" value={this.value} onIn put={(e) => this.handleInput(e)} />;
}
}
ElementInternals — ключевой API для FAE, предоставляющий
методы:
setFormValue(value: any, state?: File | string | FormData):
связывает значение компонента с формой;setValidity(validityState: ValidityState, message?: string, anchor?: HTMLElement):
управляет валидацией;form: ссылка на родительскую форму;labels: возвращает связанные
<label>.Компонент автоматически отслеживает атрибуты required,
disabled, и может использовать встроенные методы
проверки:
validate() {
if (this.required && !this.value) {
this.internals.setValidity({ valueMissing: true }, 'Поле обязательно для заполнения');
} else {
this.internals.setValidity({});
}
}
FAE поддерживают стандартные события формы, такие как
submit, reset. При сбросе формы
(form.reset()) можно сбросить внутреннее состояние
компонента через метод internals.setFormValue('') или
вручную обновить @Prop() value.
connectedCallback() {
const form = this.internals.form;
form?.addEventListener('reset', () => {
this.value = '';
this.internals.setFormValue('');
});
}
<label> и атрибутов, как у нативных
элементов.ElementInternals для кастомных элементов.<label> и формой может требовать явного управления
internals.labels.form позволяет подключать компонент к форме вне
иерархии DOM, но это требует явного указания
formAssociated = true.internals в
componentWillLoad или connectedCallback, чтобы
гарантировать доступ к API формы.@Prop() value с
internals.setFormValue при каждом изменении состояния.setValidity и при
необходимости отображать пользовательские сообщения ошибки.reset через событие формы, чтобы компонент
корректно возвращался к исходному состоянию.Использование form-associated custom elements в Stencil позволяет создавать полностью совместимые с HTML-формами кастомные элементы, сохраняющие все преимущества веб-компонентов, включая инкапсуляцию, повторное использование и реактивность состояния.