Shadow DOM
Shadow DOM is a standard that encapsulates the internal document object model (DOM) structure of a web component. Encapsulating the DOM gives developers the ability to share a component and protect the component from being manipulated by arbitrary HTML, CSS, and JavaScript. The internal DOM structure is called the shadow tree. The shadow tree affects how you work with CSS, events, and the DOM.
Since not all browsers support Shadow DOM, LWC uses a synthetic shadow polyfill for Lightning Experience and Experience Cloud. A polyfill is code that allows a feature to work in a web browser.
If you use LWC outside of Lightning Experience or Experience Cloud, such as in Lightning Out, LWC renders in native shadow. See Compile-time Differences on the Salesforce Platform.
To understand the shadow tree, let’s look at some markup. This markup contains two Lightning web components: c-todo-app
and c-todo-item
. The #shadow-root
document fragment defines the boundary between the DOM and the shadow tree. Elements below the shadow root are in the shadow tree.
Let’s look at how to work with the shadow tree in each of these areas.
- CSS
CSS styles defined in a parent component don’t leak into a child. In our example, a
p
style defined in thetodoApp.css
stylesheet doesn’t style thep
element in thec-todo-item
component, because the styles don’t reach into the shadow tree. See CSS.- Events
To prevent exposing a component’s internal details, if an event bubbles up and crosses the shadow boundary, some property values change to match the scope of the listener. See Event Retargeting.
- Access Elements
Elements in a shadow tree aren’t accessible via traditional DOM querying methods. Code can’t use
document
ordocument.body
to access the shadow tree of a Lightning web component. For example, code can’t calldocument.querySelector()
to select nodes in a Lightning web component’s shadow tree. To access its own shadow tree, a Lightning web component callsthis.template.querySelector()
. See Access Elements the Component Owns.- Access Slots
A slot is a placeholder for markup that a parent component passes into a component’s body. DOM elements that are passed to a component via slots aren’t owned by the component and aren’t in the component’s shadow tree. To access DOM elements passed via slots, call
this.querySelector()
. The component doesn't own these elements, so you don’t usetemplate
. See Pass Markup into Slots.- Test Components
Watch Salesforce Developer Evangelist Alba Rivas explain the Shadow DOM.
Don’t use these DOM APIs to reach into a component’s shadow tree in orgs that use Lightning Locker. If you’re using a third-party JavaScript library that uses these DOM APIs to reach into a component’s shadow tree, work with the library author to file and fix issues.
Document.prototype.getElementById
Document.prototype.querySelector
Document.prototype.querySelectorAll
Document.prototype.getElementsByClassName
Document.prototype.getElementsByTagName
Document.prototype.getElementsByTagNameNS
Document.prototype.getElementsByName
document.body.querySelector
document.body.querySelectorAll
document.body.getElementsByClassName
document.body.getElementsByTagName
document.body.getElementsByTagNameNS
Lightning Locker prevents you from breaking shadow DOM encapsulation between Lightning web components by blocking these APIs. However, in Aura components version 39.0 and earlier, Lightning Locker is disabled at the component level, so an Aura component could have code that fails.
These APIs aren’t restricted by Lightning Web Security (LWS). LWS prevents you from breaking shadow DOM encapsulation by enforcing a value of closed
on the ShadowRoot's mode
property for all components.
The Shadow DOM polyfill includes a patch to the MutationObserver
interface. If you use MutationObserver
to watch changes in a DOM tree, disconnect it or you will create a memory leak. Note that a component can observe mutations only in its own template. It can't observe mutations within the shadow tree of other custom elements.
To easily convert components from synthetic DOM to native shadow DOM, use the lwc-codemod tool. The tool adds the static shadowSupportMode
property to a synthetic DOM component.
For more information, see the lwc-codemod documentation.