Light DOM is a Lightning Web Components feature that’s been Generally Available in Lightning Experience, Experience Cloud, LWC OSS (Open Source), and all versions of the Salesforce mobile app since Summer ’23.
Lightning web components, by default, render in shadow DOM, which provides strong encapsulation and security for your components. However, at the same time, it prevents global styling and blocks third-party integrations that introspect the internals of your components. Light DOM is a feature that can be enabled granularly in selected components, so that shadow DOM doesn’t affect them.
How does light DOM work?
Let’s use a very simple Lightning web component as an example.
In the example above, the component’s default shadow DOM prevents the
<p> element using browser query APIs.
To activate light DOM for a component, you need to both specify the light
lwc:render-mode template directive on the
<template> tag of the component. Both changes are needed due to the way in which Lightning web components compile.
When you activate light DOM in a component, the component markup gets attached to the host element instead of its shadow tree. You can then access the markup from other components on the page like any other content in the document host that’s not protected by shadow DOM.
Light DOM components allow for the usage of standard browser query APIs like
querySelectorAll. In this case, instead of using
this.template.querySelector, you have to use
Or more simply, you can often just use the
lwc:ref directive in both cases (shadow and light DOM components) and skip the
When to use it, and when not to use it
Light DOM is an opt-in for each individual component. Its effects won’t apply to other components unless they also opt in. Note that base components always render in shadow DOM.
We recommend enabling light DOM if you have libraries that need to access component internals using standard browser query APIs, apply global styling, or need more flexibility to implement accessibility best practices, as long as the component does not expose sensitive data. We’ll cover these use cases more in-depth in the next section.
We don’t recommend enabling light DOM for a component if that component surfaces or works with sensitive data. Using light DOM removes shadow DOM encapsulation and exposes components to DOM scraping. So, be aware of this important consideration.
Use cases enabled by light DOM
Light DOM enables several use cases that were not previously supported.
1) Support of libraries that need access to a component’s internals
Light DOM enables the usage of libraries that need access to component internals. A good example of this are analytics libraries used in Experience Cloud sites, such as Google Analytics, as they need access to component internals to obtain better results.
We can test this use case, including the previous
helloCodey component, in a parent
mascotChanger component as follows.
Note that although the queried paragraph belongs to the
helloCodey component, we’re able to access it with
this.template.querySelector, because it belongs to the child light DOM. However, if the
helloCodey component wouldn’t have light DOM enabled,
querySelector would have returned
helloCodey component internals as follows.
2) Easier implementation of deeply-nested components
Another example in which this can be useful is to implement complex, deeply-nested components. In that case, you may prefer to have a single shadow DOM component at the top level and light DOM components within to avoid overhead. For instance, a custom data table component can just have one big shadow DOM component around the whole thing, rather than a shadow for every table row and table cell.
This implementation makes it easier to query your own elements from the top-level component in your hierarchy, and also to implement accessibility. Additionally, there is a slight perf improvement in some use cases to using light DOM over shadow DOM, which is mostly due to the overhead of just creating the additional shadow nodes.
3) Global styling
Light DOM also facilitates global styling, as it allows CSS styles to cascade into the component markup. For instance, a light DOM component can set a style that is loaded and then applied once for all the light DOM components on the page. Injecting global styles through light DOM is only supported on Experience Cloud sites, CMS content editor, or Sales Enablement.
For instance, let’s define a
colorChanger component as follows.
The blue background color will be applied to the paragraphs of all the
helloCodey component instances on the page as it’s light DOM enabled.
In most cases, you won’t want your style to leak into other components. That’s still possible for light DOM components. You just need to place those style rules into a
*.scoped.css file, so they are scoped to the light DOM component. Scoped CSS is written exactly the same as regular CSS, but it’ll just apply only to that component without leaking out.
Note that if style rules are loaded globally as static resources on a Lightning Experience page or Experience Cloud site, they will be unscoped and applied to both light DOM but also shadow DOM components, as synthetic shadow won’t prevent them from leaking. This is a limitation that will be solved once native shadow is fully supported (currently in Developer Preview). When native shadow is enabled, only light DOM-enabled components will inherit global styles.
4) More flexible implementation of accessibility best practices
Light DOM enables a component to reference the
d of an element that lives in another light DOM-enabled separate component. This allows you to link two elements using i
aria attributes, granting you extra flexibility for implementing accessibility best practices in your projects. Let’s improve our
mascotChanger component to demonstrate this.
Please note that Salesforce is currently working with the W3C to add new standards, so that native shadow DOM can participate in these accessibility patterns. This means that, in the future, this light DOM use case won’t be needed. As part of our accessibility efforts, we also sponsored Igalia to partially implement ARIA Element Reflection, which is now fully supported in Safari and partially in Chrome. If you want to know more about this topic, take a look at our cross-root-aria proposal, the repo for the Accessibility Object Model working group.
The following table summarizes the use cases and where they are supported.
|Experience Cloud||Lightning Experience||Salesforce Mobile Apps||LWC OSS / LWR on Node.js*|
|Support of libraries that need access to component’s internals||Yes||Yes||Yes||Yes|
|Easier implementation of deeply-nested components||Yes||Yes||Yes||Yes|
|More flexible implementation of accessibility best practices||Yes||Yes||Yes||Yes|
*If using native shadow DOM instead of synthetic shadow. Native shadow is the default for LWC OSS and LWR on Node.js.
When working with light DOM, there are some additional considerations to take into account, including:
- Events are not retargeted with light DOM. Read more in the developer guide.
- There’s no browser support for slots outside of shadow DOM, so they are emulated. This implies that some features, such as lifecycle hooks, are not available in them. Take a look at the documentation to know more.
- For now, light DOM-enabled components cannot be packaged.
In this blog post, we’ve reviewed what light DOM is, the use cases that it enables, and the considerations to take into account to decide which components will opt-in the feature. All the examples shown on this blog are in a GitHub repo that you can try out yourself.
If you decide to go ahead and transform your shadow DOM components into light DOM ones, check out this tool created by Salesforce Engineering to simplify the migration.