Good, Bad and Ugly WebComponents

Container and collection components. How do they receive items? Do they receive items? Let’s find out!

Many times when building user interfaces one comes across container elements, i.e. elements that take a collection of items and display them.

There are different ways to tell the container which items to render.

Traditionally, a template engine would render them inside a for-each construct. In React one would pass a collection via an “attribute” (e.g. <MyList items={items} />), and let the component figure out how to render its items.

With WebComponents there are a number of ways to approach this situation.

Ugly

aka “super bad”

Stringifying complex data and passing it via attribute.

<my-list
  a-attribute-type
  items='[
    {"id": 0, "name": "Item 1", "img": "//...", "text": "..."},
    {"id": 1, "name": "Item 2", "img": "//...", "text": "..."}
  ]'>
</my-list>

Needless to say, this is not a good idea. It looks similar to the React approach but really isn’t.

Bad

aka “situational”

Programmatically setting the content:

<my-list id="list" a-attribute-type></my-list>

<script>
  list
    .setItems([
      {id: 0, name: 'Item 1', img: '//...', text: '...'},
      {id: 1, name: 'Item 2', img: '//...', text: '...'},
    ])
    .render();
</script>

This approach is suitable for web apps which can’t or won’t to be be interpreted in terms of web pages.

Good

Progressively enhance content, as god intended:

<my-list a-attribute-type>
  <my-list-item item-id="0" some-attribute>
    <h3 slot="name">Item 1</h3>
    <img slot="img" src="//..." />
    <p slot="text">...</p>
  </my-list-item>
  <my-list-item item-id="1" some-attribute>
    <h3 slot="name">Item 2</h3>
    <img slot="img" src="//..." />
    <p slot="text">...</p>
  </my-list-item>
</my-list>

This

  • maintains semantics
  • makes content available before JS is loaded / when disabled
  • makes content consumable without a webcomponents polyfill
  • is in line with how native components like <select/> work

However, it does not encapsulate the rendering of the items like a React component would do. This is why the more common approach will be:


© 2022 Florian Klampfer

Powered by Hydejack v9.1.6