HTML自定义元素需通过formAssociated=true和ElementInternals接口接入表单校验,手动映射属性、调用setFormValue()和setValidity(),否则无法参与form.checkValidity()等原生校验流程。

HTML 自定义元素(Custom Elements)本身不提供数据校验能力,校验逻辑必须由开发者显式实现。它不是替代 form 校验的方案,而是封装校验行为的载体——你得自己把规则塞进去,浏览器不会自动读取 data- 或触发 setCustomValidity()。
为什么不能直接用 Custom Element 的 attribute 做校验?
自定义元素的属性(如 my-input required pattern="\d{6}")只是字符串,浏览器不会解析它们去调用原生校验 API。required、pattern 这些只对标准表单控件(input、select 等)生效,对 <my-input></my-input> 完全无效。
- 即使你在自定义元素内部渲染了一个
<input>,也得手动把外部传入的required属性映射到内部input上,否则它只是摆设 -
attributeChangedCallback不会自动触发checkValidity(),你得自己监听并调用 - 如果不显式调用
setCustomValidity(),用户点击提交时,这个自定义元素对表单整体有效性(form.checkValidity())毫无贡献
怎么让自定义元素参与表单校验流程?
核心是让它“假装”是个标准表单控件:实现 formAssociated + ElementInternals 接口。这是唯一能让它被 form.checkValidity() 识别、支持 :valid/:invalid 伪类、响应 reportValidity() 的方式。
- 必须在 class 定义中设置
formAssociated = true - 在
constructor中创建this.internals_ = this.attachInternals() - 通过
this.internals_.setValidity()或this.internals_.setCustomValidity()控制校验状态 - 必须暴露
value、name、disabled等属性,并同步到internals(例如修改value后调用this.internals_.setFormValue(this.value)) - 不要在自定义元素里写
novalidate—— 它不处理表单提交,那是外层form的事
常见错误:用 shadow DOM 隐藏 input 却忘了绑定 validity
很多人用 shadowRoot 封装一个 <input type="email">,以为这样就能复用原生校验。错。shadow 内部的 input 对外不可见,form 根本不知道它的存在,也不会读它的 validity 状态。
- 即便你监听了内部
input的blur并调用input.checkValidity(),结果也只是内部input的,不影响外层表单 - 正确做法是:把内部
input的validity映射出来,再通过this.internals_.setValidity(...)向外暴露 - 特别注意
valueMissing:如果内部input是空的,但你的自定义元素没显式设置this.internals_.setValidity({ valueMissing: true }),form.checkValidity()仍会返回true - 别依赖
input.validity直接赋值给internals.setValidity()——ValidityState是只读对象,必须构造新对象传入
要不要用第三方库?
除非你正在开发一套跨项目复用的 UI 组件库,否则不建议为单个表单专门写 Custom Element 做校验。它成本高、调试难、兼容性有坑(attachInternals() 在 Safari 16.4+ 才稳定支持)。
立即学习“前端免费学习笔记(深入)”;
- 简单场景:直接用
input+data-元数据 + JS 校验更轻量、更可控 - 复杂联动:优先考虑用
form+novalidate+ 统一 JS 校验器,而不是拆成多个自定义元素各自维护 validity - 真要用 Custom Element,务必测试
form.reportValidity()是否能触发你的元素的错误提示——这是唯一能验证它是否真正接入校验链的手段
attachInternals() 和 setFormValue() 必须成对出现;还有人把 setCustomValidity('') 写成 setCustomValidity(null),导致后续所有校验失效。这些细节不跑一遍真实表单提交,很难发现。



















