is属性仅在whatwg规范白名单的约20个原生标签(如button、input等)上有效,且必须通过customelements.define("tag", class, {extends: "tag"})注册,构造函数首行须调用super(),否则无效。

直接说结论:is 属性不是“加个属性就能扩展”的快捷方式,它只在特定原生标签上生效,且必须配合 customElements.define() 的 { extends: "xxx" } 选项注册,否则完全无效。
哪些 HTML 标签能用 is 属性
不是所有标签都支持。浏览器只认 WHATWG 规范白名单里的约 20 个原生标签,比如:button、input、textarea、select、option、canvas、table、tr、td、p、video、img 等。
div、span、section 这类通用容器标签不在此列——写 <div is="my-thing"> 解析后仍是 <code>HTMLDivElement,不会触发自定义类构造函数。
- 查最新白名单:直接看 WHATWG HTML spec “Customized built-in elements” 小节
- 常见误用:
<p is="highlight"></p>能注册成功,但若没在白名单里(如旧版 Chrome),照样降级为普通HTMLParagraphElement - 兼容性注意:Safari 对部分标签(如
meter、progress)支持较晚,生产环境建议加降级 fallback
customElements.define() 必须带 { extends: "xxx" }
只写 customElements.define("my-btn", MyBtn) 是不够的。浏览器看到 <button is="my-btn"></button> 时,会去查 customElements.get("my-btn") 是否存在,再检查它的 extends 配置是否匹配当前标签名。
- 漏掉
extends→is被忽略,元素仍是原生类型 -
extends值大小写/连字符必须和 HTML 标签名完全一致:{ extends: "BUTTON" }或{ extends: "button-" }都不匹配 - 类必须继承对应内置类:
class MyBtn extends HTMLButtonElement,不能只继承HTMLElement - 注册顺序很重要:脚本必须在含
is的 HTML 解析前执行;放在底部或DOMContentLoaded后容易失效
constructor 里第一行必须是 super()
这不是可选建议,而是 WebIDL 绑定层强制要求。漏掉或挪到后面,实例化就会失败,控制台报 Failed to construct 'HTMLButtonElement': Please use the 'new' operator。
-
super()初始化底层 DOM 关联,比如表单收集逻辑、this.disabled、this.value、this.focus()行为 - 在
super()前给this.xxx赋值会触发Illegal constructor -
connectedCallback里补super()没用——它只在构造阶段起作用 - 典型症状:
<button is="my-btn" value="submit"></button>中this.value是undefined,但this.getAttribute("value")能取到字符串
is 属性不支持运行时切换
HTML 规范明确写着:is 只在元素创建时读取一次,后续修改不触发任何升级或替换。你执行 el.setAttribute("is", "span-blue"),el.constructor 不变,instanceof 判断仍为原类。
-
attributeChangedCallback监听is并调super()?无效,原型链已固化 - 真要动态行为,得把逻辑从
constructor移到connectedCallback,靠普通属性(如mode="blue")驱动分支 - 硬切类型代价高:手动销毁旧节点、新建目标类型、迁移子节点——仅限极特殊场景
- Vue 的
:is和原生is完全无关,混用会导致表单提交失效、disabled不同步、可访问性语义丢失
最容易被忽略的是三点:注册时机早于 HTML 解析、extends 字符串与标签名严格一致、super() 在 constructor 首行不可省略。少一个,is 就只是个普通字符串属性。











