Chrome 117及118 Beta中contenteditable元素为何无法再次聚焦?
Chrome 117+中Slot包裹的Contenteditable元素失焦后无法重新聚焦的问题与解决方案
问题描述
开发自定义元素时,其shadowRoot内仅包含<slot>,slot中嵌入了contenteditable="true"的div。在Chrome 117及118 Beta版本中出现异常:第一次点击该div可正常获取焦点并输入,点击其他区域失焦后,再次点击div无法重新获取焦点。Mac平台下其他浏览器无此问题。
最小复现代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> </head> <body> <input id="test-input" /> <example-component> <div contenteditable="true"> <h1>Hello World!</h1> <p>This is an example</p> </div> </example-component> <script> customElements.define( "example-component", class extends HTMLElement { constructor() { super(); this.attachShadow({ mode: "open" }); this.shadowRoot.innerHTML = ` <slot></slot> `; } } ); </script> </body> </html>
原因分析
这是Chrome 117版本引入的焦点管理Bug:当slot内的可编辑元素失焦后,Chrome的焦点追踪逻辑错误地将焦点关联到自定义元素的shadowRoot,而非实际的可编辑节点,导致后续点击无法正确触发焦点切换。
解决方案
以下三种方案均可修复该问题:
方案一:给自定义元素添加tabindex属性
让自定义元素成为可聚焦元素(但不参与Tab导航),修正Chrome的焦点追踪逻辑:
<example-component tabindex="-1"> <div contenteditable="true"> <h1>Hello World!</h1> <p>This is an example</p> </div> </example-component>
方案二:在shadowRoot中添加隐藏的可聚焦锚点
在shadowRoot内插入一个不可见的可聚焦元素,作为焦点的锚点:
customElements.define( "example-component", class extends HTMLElement { constructor() { super(); this.attachShadow({ mode: "open" }); this.shadowRoot.innerHTML = ` <slot></slot> <div tabindex="-1" style="position:absolute; width:0; height:0; overflow:hidden;"></div> `; } } );
方案三:手动监听点击事件强制聚焦
通过点击事件监听,直接将焦点设置到目标可编辑元素:
customElements.define( "example-component", class extends HTMLElement { constructor() { super(); this.attachShadow({ mode: "open" }); this.shadowRoot.innerHTML = ` <slot></slot> `; this.addEventListener('click', (e) => { if (e.target.isContentEditable) { e.target.focus(); } }); } } );
内容的提问来源于stack exchange,提问作者Jason Sperske
相关产品推荐
相关产品推荐

