is属性仅对whatwg规范白名单中约20个原生标签(如button、canvas)生效,必须配合customelements.define()的{extends:"xxx"}严格注册,且注册须早于html解析;任一环节(extends缺失、大小写/连字符错误、super()未首行调用、polyfill加载过晚)均导致静默失效。

直接用 customElements.define() 配 { extends: "xxx" } 注册,且必须在 HTML 解析前执行;漏掉 extends、大小写错、或注册晚于含 is 的标签,都会静默失效——浏览器不报错,但元素就是普通原生类型。
is 属性只对特定原生标签生效,不是所有标签都能加
浏览器只认 WHATWG 规范白名单里的约 20 个标签,比如 button、canvas、table、tr、td、p、input、option。给 div 或 span 加 is="my-thing" 完全没用,DOM 中仍是 HTMLDivElement 或 HTMLSpanElement,不会触发你的类。
查证方式:打开 WHATWG Customized Built-in Elements spec,看 “Elements that can be customized” 表格。
<div is="my-button"> → 浏览器无视,实例是 <code>HTMLDivElement-
<button is="my-button"></button>→ 有效,但前提是已用customElements.define("my-button", ..., { extends: "button" })注册 - 想扩
canvas?只能用<canvas is="my-renderer"></canvas>,不能用<my-renderer></my-renderer> -
customElements.define("my-btn", MyBtn, { extends: "button" })→ 对应<button is="my-btn"></button> - 写成
{ extends: "btn" }或漏掉整个对象字面量 → 实例仍是HTMLButtonElement,不走MyBtn构造函数 -
extends值必须是小写字符串,且必须与原生标签名完全一致("canvas"不是"Canvas",也不是"htmlcanvaselement") - 注册名是
"my-renderer",HTML 里就必须写<canvas is="my-renderer"></canvas>;写成"myRenderer"、"my-renderer "或"MyRenderer"都失败 - 类必须继承对应内置类:
class MyButton extends HTMLButtonElement,不能只继承HTMLElement -
constructor()第一行必须是super();挪到第二行、漏写、或在super()前访问this.disabled,会直接报Failed to construct 'HTMLButtonElement' - 注册代码必须同步执行,或确保早于含
is的标签解析;放在DOMContentLoaded之后,首次渲染就 fallback 成HTMLUnknownElement - 推荐用官方
@webcomponents/custom-elements,CDN:https://unpkg.com/@webcomponents/custom-elements@1.1.2/custom-elements.min.js - polyfill 必须在任何
customElements.define()调用之前加载,否则注册失败且无提示 - 最佳位置:放在
末尾,或开头,避免 DOM 已解析完再加载
注册时 extends 选项不可省,且值必须严格匹配宿主标签
is 属性本身只是个“触发器”,真正决定元素类型的是 customElements.define() 的 extends 配置项。没它,is 就是纯字符串,浏览器直接跳过。
注册名、is 值、类继承三者必须严丝合缝
这三者任何一处差一个连字符、大小写或空格,整个机制就断链,而且断得悄无声息。
旧浏览器必须加 polyfill,且加载时机不能错
Chrome 67+、Firefox 63+、Safari 10.1+ 原生支持,IE 和旧 Edge 完全不支持。不加 polyfill,is 扩展在这些环境里等于不存在。
最容易被忽略的其实是“静默失败”:你改错一个连字符、漏掉 extends、或者 super() 写晚了,浏览器既不报错也不警告,只是安静地当它是个普通按钮或 canvas 处理——然后你发现 this.width 是 undefined、this.focus() 报 Illegal invocation,却找不到原因。











