Skip to content

INOS-soft/ember-shadow-dom

 
 

Repository files navigation

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.

🛠 Experimental support for SSR/FastBoot in Chrome via a flag (see https://web.dev/declarative-shadow-dom/).

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

Compatibility: Not all browsers support Shadow DOM (v1) yet, see CanIUse to see if your target browsers support this new feature.

npm version

Compatibility

  • Ember.js v3.16 or above
  • Ember CLI v2.13 or above
  • Node.js v10 or above

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

  • @mode (string) - The mode of the Shadow Root, defaults to 'open'. Can be 'open' or 'closed'. Note that 'closed' mode prevents you from querying into the DOM of your components in tests.
  • @tagName (string) - This defaults to 'div', but can be any valid element tag name used in HTML. Setting this argument changes the top level element that the shadow root is attached to.

FastBoot/SSR (experimental)

This addon supports ShadowDom in SSR (meaning your styles will remain the same on initial render and not change when rehydrated) via a new experimental flag ONLY in Chrome 85+ with the following flag enabled:

chrome://flags/#enable-experimental-web-platform-features

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>

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.

About

Write templates for your components inside of a Shadow DOM root.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 76.6%
  • HTML 15.2%
  • Handlebars 8.2%