Home

Awesome

ember-shadow-dom

Write templates for your components inside of a Shadow DOM root. Allows encapsulating styles (CSS) and markup (HTML) but using templates like you're used to.

🛠 Support for SSR/FastBoot in Chrome 90+, Release notes.

🤔 Not sure what Shadow DOM is? Check out this MDN article.

Compatibility: Most browsers support Shadow DOM (v1), except for IE11, see CanIUse for details

npm version

Compatibility

If using Ember < 3.20, this addon will use the private version of {{in-element}} via a polyfill.

Installation

ember install ember-shadow-dom

Usage

This addon provides a component called ShadowRoot.

<ShadowRoot>
  <style>
    .internal { color: red; }
  </style>

  <span class='internal'>Internal</span>
</ShadowRoot>

This makes the encapsulating component's children a shadow root.

Slots

In Shadow DOM you can generally use <slots>, but with Ember you can just use {{yield}}.

{{! components/test.hbs }}
<ShadowRoot>
  <style>
    .internal { color: red; }
  </style>

  <span class='internal'>
    {{yield}}
  </span>
</ShadowRoot>

And you can call the component:

<Test>
  Hello World!
</Test>

And the contents Hello World! will be inside the shadow root. If you need multiple "slots", you can use ember-named-blocks-polyfill.

{{! components/card.hbs }}
<ShadowRoot ...attributes>
  <style>
    .title { color: red; } .body { margin-top: 1rem; }
  </style>

  <header class='title'>
    {{yield to='title'}}
  </header>

  <div class='body'>
    {{yield to='body'}}
  </div>
</ShadowRoot>

And use the component like so:

<Card class='custom-card'>
  <:title>
    My title
  </:title>

  <:body>
    Some content here!
  </:body>
</Card>

API

<ShadowRoot> Component

Arguments

FastBoot/SSR

This addon supports ShadowDom in SSR (meaning your styles will remain the same on initial render and not change when rehydrated) in Chrome 90+

Other browser vendors should follow, but there is some risk that it never happens. Details here: https://www.chromestatus.com/feature/5191745052606464

Testing

Components with a open shadowroot can be tested using qunit-dom like so:

let root = find('#internal').shadowRoot;
assert.dom('.block', root).hasText('template block text');

Where the template looks like:

<ShadowRoot id='internal'>
  <div class='block'>template block text</div>
</ShadowRoot>

Note: check out https://github.com/salesforce/kagekiri for piercing the shadow for querying elements

Contributing

See the Contributing guide for details.

Attribution

Thanks to @rwjblue for realizing that {{in-element}} can be used for the shadow root!

License

This project is licensed under the MIT License.