Если вы знакомы с Веб-компонентами или Пользовательскими элементами, возможно, вы слышали, что вы можете расширять не только HTMLElement, но и другие нативные элементы, такие как HTMLInputElement.

class myInput extends HTMLInputElement {
   ...
}
customElements.define("my-input", myInput, { extends: 'input' });

и используется так:

<input type="text" is="my-input">

Преимущества расширения существующего нативного элемента многочисленны:

  1. Ваши клиенты будут знакомы со свойствами, атрибутами и событиями этого нового компонента.
  2. У вас будет очень четкий набор правил, которым нужно следовать
  3. Такие фреймворки, как Angular или Vue.js, будут знать, как работать с этим компонентом.

Не в списке преимуществ, но определенно является плюсом… если это старый браузер, такой как Internet Explorer 11, то такой элемент, как ввод, все равно будет отображаться в обычном режиме. Если это текстовый ввод, он будет выглядеть как текстовый ввод. Таким образом, он может выглядеть лучше только в том случае, если вы загружаете модуль после проверки типа браузера.

Реализация немного отличается от обычного пользовательского элемента, и причина этого в том, что мы не можем отрисовать текущий элемент (этот), поскольку он уже отрендерен. Мы также не можем удалить его из DOM, так как это канал связи между браузером и нашим компонентом. Мы также не можем добавить к нему дочерние элементы, потому что такие элементы, как input, не принимают дочерних элементов. Так что же нам делать?

Вы можете добавить родственный элемент и при необходимости скрыть текущий элемент.

render(){
  this.style.display = "none";
  this.wrapperEl = document.createElement("div");
  this.wrapperEl.innerHTML = `<div>My Input</div>`;
  this.after(this.wrapperEl);
}

Вы должны помнить об удалении родственного элемента, когда компонент удаляется из DOM:

disconnectedCallback() {
  this.wrapperEl.remove();
}

Что касается доступности, если вы делаете ввод, я предлагаю убедиться, что основной элемент, который вы рисуете, является фокусируемым (добавьте tabIndex = 0), чтобы убедиться, что элемент будет в фокусе при переходе между входами, но сделать убедитесь, что внутренняя навигация, если она у вас есть, не фокусируется. Идея формы заключается в том, что нажатием TAB вы можете переходить с одного поля на другое. Внутри (когда пользователь сосредоточен на фактическом компоненте) вы можете включить клавиши для внутренней навигации, например вверх/вниз. Как и Селект.

Один из компонентов, которые я реализовал, я сделал браузер изображений, поэтому значением будет идентификатор изображения, и он расширяет ввод.

Он очень похож на текстовый ввод, за исключением того факта, что он имеет кнопку просмотра и открывает модальное окно, позволяющее просматривать. Компонент зависит от Bootstrap для открытия модального окна. В этом случае также необходимо удалить модальное окно на disconnected, если это необходимо.

Вы должны знать, какие события вы должны запускать при обновлении данных, например change, input и т. д. При обновлении значения вам также необходимо отправить соответствующее событие, поскольку оно не будет отправлено автоматически:

this.dispatchEvent(new Event("input"));

Лично мне не нравится использовать фреймворки для компонентов. Я думаю, что если код слишком сложен, значит, что-то не так, и его нужно разбить на более мелкие компоненты или классы. Но это я, важно то, что независимо от вашей реализации, результатом будет простой способ для ваших клиентов использовать компонент. Что скрывается за черным ящиком, зависит от вас, а не от клиента.

Я надеюсь, что это помогло вам, и я хотел бы прочитать ваши комментарии и предложения.

Удачи ;-)