Shadow DOM
VisionPlayer can use Shadow DOM for ultimate encapsulation, consistent theming, and style robustness – even in hostile CSS environments.
What is Shadow DOM?
Shadow DOM creates a protected, isolated DOM subtree for your component’s internal UI. No external CSS or JavaScript can leak in, override your styles, or manipulate your player’s internals. This guarantees your player always looks and works as designed – regardless of global CSS chaos.
- Shadow mode creates a mirrored, encapsulated
<vision-player>inside the original one. - All classes, IDs, and CSS variables are automatically copied over for seamless theming.
- Set the width/layout on the outer element – the inner player will fill it.
- Switch between Shadow and Non-Shadow with minimal code or config changes.
- Use the same selectors and CSS variables for both modes. Per-instance styling "just works".
When to use this?
- Whenever you need bulletproof, isolated UI (e.g. in CMS, complex apps, or "hostile" CSS environments)
- When you want to ensure your player always looks and behaves as intended, regardless of global styles
- For scenarios requiring maximum security (preventing JS/CSS leaks to internals)
Why are there two <vision-player> elements in shadow mode?
When you activate shadow mode, VisionPlayer creates a second internal <vision-player> element inside the ShadowRoot. This means:
-
Outer
<vision-player>:- Remains in the normal document flow
- Used for layout, width, selectors, and hosting attributes/classes/IDs
- Ensures your CSS selectors for
vision-playerwork in both modes
-
Inner
<vision-player>(Shadow Host):- Lives inside the ShadowRoot
- Hosts the actual player UI and logic
- Mirrors (copies) classes, IDs, and CSS variables from the outer element
- Always gets an additional
.is-shadowclass for precise targeting
In non-Shadow mode: There is only one
<vision-player>element, behaving like any standard web component.
In Shadow mode: There are two<vision-player>tags: the outer (for layout/config) and the inner (for encapsulated UI).
This design keeps the developer experience and theming nearly identical between both modes!
How class, ID, and CSS variable mirroring works
To make theming and per-instance customization as easy and predictable as possible:
- All classes and IDs from the outer
<vision-player>are mirrored onto the inner ShadowRoot<vision-player> - All supported `vip-xxx` CSS variables set on the outer element (e.g., via a style block or inline) are made available in the ShadowRoot as well
- The
.is-shadowclass is automatically added to the inner player in Shadow mode, for targeted styling
Example
<vision-player id="player42" class="vip-theme-dark" data-vip-config='{"dom":{"shadow":"closed"}}'></vision-player>
Results in:
- Outer:
<vision-player id="player42" class="vip-theme-dark" ...> - Inner (in ShadowRoot):
<vision-player id="player42" class="vip-theme-dark is-shadow">
This means your CSS like:
vision-player.vip-theme-dark { ... }
and
:host(.vip-theme-dark) { ... }
will work exactly the same, regardless of Shadow mode.
Important: Width and Layout in Shadow Mode
Note: In Shadow mode, the outer <vision-player> acts as the layout container for the player.
By default, VisionPlayer tries to set its width to 100%.
However, due to Shadow DOM scoping, this may not always work as expected!
If your player appears collapsed or invisible, make sure to set an explicit width on the outer element – for example:
<vision-player style="width: 100%"></vision-player>
or via CSS:
vision-player { width: 100%; }
The inner player will always stretch to fill the outer host.