is属性仅对html规范白名单中的原生标签(如button、canvas等)生效,必须配合customelements.define()的extends选项注册,且大小写敏感;非支持标签或未声明extends时无效,与vue的:is无任何兼容性。

is属性只对特定原生标签生效,不是通用“增强开关”
浏览器不会因为你给任意标签加 is 属性就自动升级行为。它只在明确支持的原生标签上起作用,比如 button、canvas、table、tr、option 等——这些都在 HTML 规范白名单里。
常见错误现象:<div is="my-button"> 或 <code><p is="highlight"></p> 完全无效,DOM 中仍是普通 HTMLDivElement 或 HTMLParagraphElement,不触发任何自定义逻辑。
- 必须用支持的宿主标签:只能写
<button is="my-button"></button>,不能写<my-button></my-button>(后者是 autonomous custom element,走另一套注册路径) - 注册时必须显式声明
{ extends: "button" },否则即使写了<button is="my-button"></button>,实例也还是HTMLButtonElement,不走你的类构造函数 -
is值大小写、连字符、空格全部敏感:注册了customElements.define("my-btn", MyBtn, { extends: "button" }),HTML 里就必须写<button is="my-btn"></button>,写成myBtn或MyBtn都失败
customElements.define() 的 extends 选项是 is 属性生效的唯一前提
没有 { extends: "xxx" },is 属性就是纯装饰性字符串,浏览器直接忽略。这个选项不是可选参数,而是强制绑定条件。
使用场景很明确:目标是复用内置元素能力(表单提交、disabled 同步、键盘导航、可访问性语义),而不是从零造轮子。
- 继承
HTMLButtonElement才能保留form关联、click事件冒泡规则、focus()行为;继承HTMLCanvasElement才能直接调用getContext() - 如果只继承
HTMLElement,哪怕你在 HTML 里硬写<button is="my-thing"></button>,也不会生效——因为注册时没声明扩展关系 - 注册顺序无关紧要,但必须在解析到含
is的标签前完成;否则首次渲染会 fallback 成未知元素(HTMLUnknownElement)
Vue 的 :is 和原生 is 完全不兼容,混用必出问题
Vue 2 中的 <button is="my-component"></button> 是 Vue 模板编译器自己解析的语法糖,和 Web Components 规范无关;Vue 3 已移除该写法,仅保留 <component :is=""></component> 形式。
而原生 is 是 HTML 标准的一部分,依赖浏览器原生 Customized Built-in Elements 机制。两者运行时无任何交集。
- 在 Vue 模板里写
<button is="my-btn"></button>,Vue 2 可能劫持该属性做组件替换,但 Web Components 注册未触发,结果既不是原生按钮,也不是你定义的类实例 - Vue 3 不再识别
is作为指令,但若你同时用了defineCustomElement+app.component()注册同名组件,容易造成命名冲突和行为错乱 - 跨框架复用时,只有原生
is路径能保有底层语义;Vue 的:is本质是渲染器绕过 HTML 解析器,生成的是普通 DOM 元素,不改变节点类型
自定义元素状态追踪必须手动桥接,无法靠 is 属性自动实现
is 属性本身不携带状态,也不参与生命周期管理。它只是告诉浏览器:“请把这个原生标签实例化为你注册过的那个扩展类”。所有状态同步、属性响应、DOM 更新,都得靠你自己在类中实现。
如果你需要映射组件状态到 DOM 属性或 dataset,唯一可行路径是:在自定义元素类的生命周期钩子里主动操作。
- 在
connectedCallback中初始化状态监听,比如绑定this.dataset.state或观察attributeChangedCallback -
observedAttributes必须显式声明,否则attributeChangedCallback不会触发;且只监听 attribute 变更,不响应 property 赋值(如el.disabled = true不触发) - 想响应 property 变更,得在 setter 中手动同步到 attribute 或 dataset,或者用
Object.defineProperty重写原型上的属性
真正关键的链路不在 is 这个属性本身,而在你注册时是否传了 extends、类是否正确继承对应原生接口、以及你有没有在生命周期里把状态和 DOM 真正桥接起来——这三者缺一不可,漏掉任何一个,is 就只是个摆设。











