I’ve been working with https://lit.dev elements and want to summarize what I’ve learned about Shadow DOM and Focus:
- When a custom element is created with
document.createElement('my-el')it’s constructor is run. It has anownerDocument, butisConnectedisfalseandshadowRootis null. - When the element is
appended to a DOM element it becomes connected to the document.isConnectedwill be true and theconnectedCallbackis enqueued by the browser, even if it may not run immediately. A call togetRootNode({composed: true})will return the document. - When
attachShadowis called, theshadowRootwill be initialized and take over the elements place in the render tree. That means that past this point, any element in the light dom that’s not assigned to a slot will not have anyoffsetParent, which means that the element has no render box and is not considered being rendered. - The element being rendered is one of the requirements for being a
focusable area:
- the element’s tabindex value is non-null, or the element is determined by the user agent to be focusable;
- the element is either not a shadow host, or has a shadow root whose delegates focus is
false; - the element is not actually disabled;
- the element is not inert;
- the element is either being rendered, delegating its rendering to its children, or being used as relevant canvas fallback content.
Thus, if you want to call focus on an element in light dom of a custom
element and have it actually move the focus and dispatch the focus event,
ensure all the shadow dom slots are initialized.