is属性仅对whatwg规范白名单中的约20个原生标签有效,且必须配合customelements.define()中{extends:"xxx"}选项及继承对应内置类(如htmlbuttonelement)才能触发自定义元素升级,否则is仅为普通字符串。

is 属性不是“给任意标签加个自定义行为”的快捷键,它只在浏览器解析 HTML 时,对特定原生标签(如 button、canvas、table 等约 20 个)起作用;漏掉 customElements.define() 的 { extends: "xxx" } 选项,或类没继承对应内置类(如 HTMLButtonElement),is 就是纯字符串,不触发任何升级。
为什么 <div is="my-panel"> 完全无效
<p>浏览器根本不会尝试升级 <code>div —— 它不在 WHATWG 规范的“可扩展内置元素”白名单里。类似地,span、section、article 等也不支持。你写 <div is="my-panel">,DOM 中生成的永远是 <code>HTMLDivElement 实例,instanceof MyPanel 为 false,生命周期钩子不会执行,所有自定义方法都不可访问。
想扩展现有语义又不想从零实现?只能换支持的宿主标签,比如用 <p is="word-count"></p> 替代 <div is="word-count">,前提是 <code>p 在白名单中且已注册 { extends: "p" }。
customElements.define() 必须带 { extends: "xxx" }
这是 is 生效的唯一前提。没有它,哪怕 HTML 写了 <button is="my-btn"></button>,实例仍是原生 HTMLButtonElement,不走你的类构造函数。
- 注册名和
is值必须完全一致:大小写、连字符、空格全部敏感 ——customElements.define("my-btn", MyBtn, { extends: "button" })对应<button is="my-btn"></button>,写成"MyBtn"或"mybtn"都失败 - 类必须继承对应内置类:
class MyBtn extends HTMLButtonElement,不能只继承HTMLElement - 注册代码必须早于含
is的 HTML 解析,放在<script></script>标签内同步执行最稳妥;放在DOMContentLoaded后就晚了,首次渲染会 fallback 成普通按钮
构造函数里 super() 是硬性门槛,不是可选步骤
继承 HTMLButtonElement 或 HTMLCanvasElement 后,constructor() 第一行必须是 super()。它负责把底层 DOM 节点绑定到 JS 实例,并初始化 this.value、this.width、this.disabled 等原生属性。
漏掉、挪后、或在 super() 前给 this.xxx 赋值,会导致:
-
this.value读不到初始值,但getAttribute("value")还能取到字符串 -
this.focus()报TypeError: Illegal invocation -
this.getContext()返回null(对canvas) -
instanceof MyBtn为false,但instanceof HTMLButtonElement仍为true
connectedCallback() 里补 super() 没用——构造阶段已结束,原型链已经断了。
is 属性不能运行时修改,也不能靠 data-is 替代
is 只在元素创建时起作用:HTML 解析阶段,或调用 document.createElement("button", { is: "my-btn" }) 时。执行 el.setAttribute("is", "other-btn") 后:
-
el.constructor.name不变 -
el instanceof HTMLButtonElement结果不变 - 所有新定义的方法、属性访问都报
undefined
data-is、data-custom 等自定义属性浏览器完全忽略,不参与类型判定。它们只是数据容器,和元素构造、原型链、内置 API 零关系。
最容易被忽略的细节:你写的 is 值哪怕只差一个连字符、一个大小写,或者注册时漏了 { extends: "canvas" },整个机制就彻底失效,而且浏览器不报错、不警告,只会安静地当它是个普通未知元素处理。











