Skip to content

Shadow DOM Design Constraints In Examples

Dimitri Glazkov edited this page Apr 23, 2015 · 40 revisions

See Design Refresher for discussion on objectives.

Simple Component

Calendar

basic-calendar

In HTML:

<basic-calendar-month></basic-calendar-month>

In JS:

var calendar = document.createElement("basic-calendar-month");

place.appendChild(calendar);

console.log(calendar.firstChild); // null

// suppose that #monthTable is an element inside of calendar
console.log(document.querySelector('#monthTable')); // null

document.body.addEventListener('click', function(evt) {
  console.log(evt.target.id); // should never return monthTable
});

document.body.addEventListener('mouseenter', function(evt) {
  console.log(evt.relatedTarget.id); // should never return monthTable
});

Constraints:

  • Implementation details are not accessible using standard DOM traversal/query APIs: Node, ParentNode, Element, etc.)
  • When traversing implementation details, you can't easily walk out.
  • Event target values do not leak implementation details.
  • Active element values do not leak implementation details.
  • You can style implementation details with scoped <style> element (Early tabs control example that illustrates the need for style scoping )
  • Style selectors in the document do not match inside of the implementation details
  • Style selectors in the implementation details do not match in the document.

Component With One Insertion Point

Basic Carousel

basic-carousel

In HTML:

<basic-carousel>
 <img id="image1" src="../basic-sequence/images/image1.jpg">
 <img src="../basic-sequence/images/image2.jpg">
 <img src="../basic-sequence/images/image3.jpg">
 <img src="../basic-sequence/images/image4.jpg">
 <img src="../basic-sequence/images/image5.jpg">
</basic-carousel>

In JS:

var carousel = document.querySelector('basic-carousel');

console.log(carousel.firstChild.id == 'image1'); // returns true

console.log(carousel.childElementCount);; // returns 5

carousel.appendChild(anotherImage); // does not break carousel

carousel.removeChild(anotherImage); // does not break carousel

console.log(document.activeElement); // never returns the elements, representing the next/previous buttons in the carousel.

Constraints:

  • Enable rendering the children of an element at an arbitrary place in the DOM sub-tree that represents the internal implementation details.
  • Element's children are are always its direct children according to standard DOM traversal/query APIs: Node, ParentNode, Element, etc.)
  • Similarly, no additional children from implementation details are detectable by these DOM APIs.
  • Mutating the list of children does not require any knowledge of the implementation details.

Component With Several Insertion Points

Pull-to-refresh

Pull-to-refresh

This has a top animation area (potentially with multiple states) and a main content area.

Modal dialog

![Modal dialog](https://raw.githubusercontent.com/wiki/w3c/webcomponents/resources/Modal Dialog.png)

A simple modal dialog may have header, body, and footer (button) insertion points.

Drawer Panel

// needs pic

Video Tutorial

Constraints:

  • Need a way to select which children go into which insertion point.
  • Let internal implementation details style children, distributed into the insertion point.
  • Let internal implementation know which child is distributed into which insertion point.
  • Distribution needs to happen before child style is computed

Nested Components

Editing Bar

my-editing-bar

Constraints:

  • The outside of implementation details is not always main document. Sometimes it's the implementation details of another component.
  • Another component's insertion point may end up being a child of the component.

Inherited Components

Basic Sequence

basic-sequence

A base class for slideshows, image carousels, and other cases where a sequence of items are shown. Could be used directly, but is primarily designed as an abstract component. For example, basic-sequence could be a base class of basic-carousel.

Page templates

These are usually proprietary layouts with more than one insertion points.

![Typical page template for a large site](https://raw.githubusercontent.com/wiki/w3c/webcomponents/resources/Typical Page Template.png)

Typical page template for a large site. The base template class defines insertion points for a number of regions. Subclassing may partially fill in these insertion points. E.g., in this example from a university web site, a particular department may want to create a subclass where the “Department/Faculty Name” insertion points has been pre-filled with the department name.

Combo box

date combo box

This combo box example has multiple insertion points:

  • An icon or label that goes in the push button (here, an orange calendar icon)
  • The contents of the combo box’s dropdown (here, a calendar)
  • The input element used for the text input portion (here, a date picker).

One would like to be able to define a general purpose <combo-box> component that handles the opening/closing and positioning of the dropdown. One would then like to be able to define subclasses that extend this to create specialized combo boxes like a <date-combo-box>, <color-combo-box>, and so on.

Icon button

![Button with icon](https://raw.githubusercontent.com/wiki/w3c/webcomponents/resources/Icon Button.png)

A base <plain-button> class defines styling, interaction states, etc. A subclass called <shield-button> wants to subclass <plain-button>, add a stock icon, and then allow users to supply the remaining content (a text label).

Constraints:

  • implementation details of the base class are hidden from the super class.
  • super class should have a choice to compose the rendering of the base class in one of its insertion points.
  • a base class may want to partially fill in an insertion point defined by a base class.

Component Use In Real World

Accessibility Checker

Accessibility Developer Tools is a tool that allows developers to include Accessibility Audits into their developer workflow. The tool traverses the DOM tree of an app (using PhantomJS) and provides a report. To make analysis of the document complete, it actually needs to traverse the composed tree.

Testing

When writing tests for components, developers frequently need to inspect the contents of the implementation details, the state of the style computation, as well distributions.

For example, when developing basic-calendar-month (or rather its nested component), the developer needs to assert that the implementation details are doing the right thing.

Constraints:

  • A way to occasionally cross style-scoping boundaries
  • A way to introspect shadow trees