必须设置{ formassociated: true }并用attachinternals(),监听内部input事件调用setformvalue()实时同步值,否则表单提交时数据为空;禁用状态也需手动同步到内部控件。

自定义元素不是“加点JS让标签动起来”,而是用标准方式把交互逻辑、样式、表单能力打包进一个可复用的<my-input></my-input>里——只要浏览器支持,它就能像<input>一样被form.elements捕获、参与验证、响应submit事件。
如何让<my-input></my-input>真正提交数据
90% 的失败案例都卡在这一步:UI渲染出来了,但表单提交时值为空。这不是 bug,是没接入表单生命周期。
- 必须在类定义中显式传入
{ formAssociated: true },否则this.attachInternals()会直接抛错 -
this.internals.setFormValue()不能只在connectedCallback里调用一次,得监听子<input>的input和change事件实时同步 - 如果内部用的是
contenteditable或textarea,注意setFormValue()只接受字符串,number或null会被转成"null"
attachShadow({ mode: 'open' })和样式隔离的实际效果
Shadow DOM 不是“万能样式罩”,它只隔离 CSS 选择器作用域,不阻断所有样式继承。
-
font-family、color、line-height等继承属性仍会从外层透入,除非你在 shadow 内显式重置 - 外部 CSS 无法通过
my-input input选中 shadow 内部的<input>,但可以用::part(input)(需配合exportparts)或:host控制宿主元素自身 - 不要在 shadow 内写
!important来对抗透入样式——优先用:host-context(.dark-mode) { ... }做主题适配
为什么不能继承HTMLInputElement
Chrome 100+ 已禁用对内置元素的扩展,Firefox/Safari 基本不支持,硬写class MyInput extends HTMLInputElement只会触发DOMException: Failed to construct 'HTMLElement': The provided tag name is not valid。
- 现实唯一可行路径是自治型自定义元素(autonomous),即自己创建
<div>容器,再把<code><input>放进去,用attachInternals()模拟表单行为 - 别试图用
extends="input"绕过限制——该语法已被移出规范,现代构建工具(如 Vite)甚至会报 warning - 若真需要原生
<input>的键盘行为(如Enter提交),必须手动监听keydown并调用this.form?.dispatchEvent(new Event('submit', { cancelable: true }))
最易被忽略的点:自定义元素的disabled状态不会自动同步到内部<input>,必须在attributeChangedCallback里监听disabled变更,并手动设置input.disabled = this.hasAttribute('disabled')——否则用户点了也无响应。











