Skip to content

Instantly share code, notes, and snippets.

@jonathantneal
Last active May 17, 2018 19:04
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonathantneal/e0cecdffb0e5163ae27ef790aa3b007f to your computer and use it in GitHub Desktop.
Save jonathantneal/e0cecdffb0e5163ae27ef790aa3b007f to your computer and use it in GitHub Desktop.
Declarative HTML Components

Declarative HTML Components

Based on the examples at WICG/webcomponents#645

Examples

Declarative HTML Component using data attributes

<!-- components.html -->
<define name="x-image" export>
  <img src="images/${this.dataset.src}">
</define>

<!-- implementation.html -->
<link rel="html" href="components.html" as="x-image" />

<x-image data-src="image.webp" />

<!-- becomes: -->
<img src="images/image.webp" />

Declarative HTML Component using attributes

<!-- components.html -->
<define name="x-image" export>
  <img class="fallback" ${this.attrs.asAttrs()} src="images/${this.attrs.src}" />
</define>

<!-- implementation.html -->
<link rel="html" href="components.html" as="x-image" />

<x-image class="some-class" src="image.webp" />

<!-- becomes: -->
<img class="some-class" src="images/image.webp" />

Declarative HTML Component using attributes and the DOM tree

<!-- components.html -->
<define name="x-image" export>
  <img class="fallback" ${this.attrs.asAttrs()} src="images/${Object(this.query(':scope > x-src')).textContent}" />
</define>

<!-- implementation.html -->
<link rel="html" href="components.html" as="x-image" />

<x-image class="some-class">
  <x-src>image.webp</x-src>
</x-image>

<!-- becomes: -->
<img class="some-class" src="images/image.webp" />

Declarative HTML Component using attributes and the DOM tree

<!-- components.html -->
<define name="x-section" export>
  <section ${this.attrs.asAttrs({ exclude: 'heading' })}>
    <h3>${this.attrs.heading}</h3>
    ${this.innerHTML}
  </section>
</define>

<!-- implementation.html -->
<link rel="html" href="components.html" as="x-section" />

<x-section class="some-class" heading="Example Heading">
  <p>Lorem ipsum dolor sit amet.</p>
</x-section>

<!-- becomes: -->
<section class="some-class">
  <h3>Example Heading</h3>
  <p>Lorem ipsum dolor sit amet.</p>
</section>

Hypothetical Helper Polyfills

This is beside the point — just stuff that could fully realize the above examples right now this very moment.

DOMStringMap#asDataAttrs

DOMStringMap.prototype.asDataAttrs = function asDataAttrs(opts) {
  return (
    Object(opts).include ? Array.from(Object(opts).include) : Object.keys(this)
  )[Object(opts).exclude ? 'filter' : 'slice'](
    Object(opts).exclude ? key => !Array.from(Object(opts).exclude).includes(key) : 0
  ).map(key => `data-${key.replace(/[A-Z]/g, '-$&').toLowerCase()}="${this[key]}"`).join(' ');
};

DOMStringMap#asAttrs

DOMStringMap.prototype.asAttrs = function asAttrs(opts) {
  return (
    Object(opts).include ? Array.from(Object(opts).include) : Object.keys(this)
  )[Object(opts).exclude ? 'filter' : 'slice'](
    Object(opts).exclude ? key => !Array.from(Object(opts).exclude).includes(key) : 0
  ).map(key => `${key.replace(/[A-Z]/g, '-$&').toLowerCase()}="${this[key]}"`).join(' ');
};

Element#attrs

Object.defineProperty(Element.prototype, 'attrs', {
  get() {
    return Array.prototype.reduce.call(
      this.attributes,
      (object, attr) => Object.assign(domStringMap, {
        [attr.name.replace(/-\w/g, $0 => $0.slice(1).toUpperCase())]: attr.value
      }),
      Object.create(DOMStringMap.prototype)
    );
  }
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment