DEV Community

Cover image for Lets Build Web Components! Part 8: Mythbusters Edition
Benny Powers 🇮🇱🇨🇦
Benny Powers 🇮🇱🇨🇦

Posted on • Updated on • Originally published at bennypowers.dev

Lets Build Web Components! Part 8: Mythbusters Edition

So far in this series, we've covered the underlying web components standards, the legacy-browser polyfills, and their implementation with vanilla javascript and a wide variety of different helper libraries.

Today, we're going to review some pernicious myths about web components and their use which seem to have cropped up lately. Many of these misconceptions are understandable, considering how young the technology is, and how the shift from the v0 web components spec to v1 with its wide adoption has changed the landscape considerably, and for the better.

Let's shine a little light on the web's own component model and learn how they make development easier and improve the experience of users, developers, and managers.

Myth: Web Components Aren't Supported By Browsers

Sometimes a picture is worth 1024 words:

Browser Table illustrating full web components support in Chrome, Opera, Safari, and Firefox, with Polyfill support on Edge, and full support in development on Edge



This screenshot was taken from https://webcomponents.org with Firefox version 65.0.1 in February 2019. It shows that all major browsers support web components specifications, with Edge soon-to-deliver support sans-polyfills. (Web Components can also be made to be supported down to IE11, but you shouldn't do that)

But isn't the proof of the pudding in the eating... or... the proof of the platform API in the deploying? If web components were not supported, we wouldn't expect to see them in the wild, and certainly not in use by large teams. However: Twitter, GitHub, dev.to, McDonalds, Salesforce, ING (PDF link), SAP, and many others all use web components in public-facing, core-business pages. In my day job at Forter, we use web components. In fact, in 2018, 10% of all reported Chrome page loads used web components.

Clearly, web components are not just a potentially-interesting future technology. They are in use, by you and users like you, on the web today.

Myth: Busted

Myth: Web Components Can't Accept Complex Data

I've seen the claim recently that web components are limited to accepting their data as strings, and therefore can't take complex objects. This misconception is particularly insidious because, like any good lie, it's half true. This misguided notion stems from a fundamental misunderstanding of the DOM and how it works.

Here follows a brief review. Feel free to Skip it if you're OK with DOM vs. HTML / attrs vs. props.

<input id="text-input" placeholder="Enter Your Text"/>
Enter fullscreen mode Exit fullscreen mode

HTML Elements and attributes are part of the HTML specification, and roughly form the D part of the DOM or Document Object Model. In the example above the <input> element has two attributes, id with the value "text-input" and placeholder with the value "Enter Your Text". Since HTML documents are by definition strings and only strings, both the attribute names and their values are strings and only strings.

When the browser parses a document, it creates JavaScript objects corresponding to each HTML element, initializing some of that object's properties with the values found at the corresponding attributes. This tree of objects comprises the OM in DOM. Properties exist on JavaScript objects.

Here's a pseudocode example of the DOM node for our input:

Object HTMLInputElement {
  tagName: 'INPUT',
  placeholder: 'Enter Your Text',
  id: 'text-input'
  ...
}
Enter fullscreen mode Exit fullscreen mode

Strictly speaking, elements can have attributes but they can't have properties, because elements are part of a document, not a DOM tree. What I mean by that is that the DOM for a given page is not the same as the HTML for that page; rather, the DOM is derived from the HTML document.

You can inspect any DOM node's properties in the dev tools elements/inspector panel. Chrome shows all DOM properties in the properties tab (look next to CSS rules), Firefox shows them under the Show DOM Properties context menu. You could also evaluate $0 while inspecting a node, or use the DOM APIs, e.g. document.querySelector('my-element').someProp;

In the case of our fledgling input, the DOM object's id property is text-input.

const input = document.getElementById('text-input');

console.log(input.id);                  // 'text-input'
console.log(input.getAttribute('id'));  // 'text-input'

input.id = 'by-property';
console.log(input.getAttribute('id'));  // 'by-property'

input.setAttribute('id', 'by-attribute');
console.log(input.id);                  // 'by-attribute'
Enter fullscreen mode Exit fullscreen mode

For many attribute/property pairs, changes to one are reflected in the other, but not for all of them. For example, an HTMLInputElement's value property represents the current value, whereas the value attribute only represents the initial value.


Back to our story

It seems some developers have reasoned thus:

  1. Attributes can only be strings
  2. HTML elements only have attributes and no properties
  3. Custom Elements are HTML elements
  4. Therefore web components can only accept strings in attributes

This reasoning would hold in a world where everyone disables JavaScript 100% of the time, but we don't live in such a world. In our world, the DOM is a rich and well-utilized part of the web platform.

Custom Elements are indeed HTML elements tied to the document, but they are also DOM nodes, swinging from the branches of the DOM tree. They can have semantic string attributes, but they can also accept complex nested data as properties, using JavaScript and the DOM.

Here's an example of how you might accomplish that using only the DOM API:

const input = document.createElement('country-input');
input.countries = [
  {name: 'Afghanistan', dialCode: '+93', countryCode: 'AF'},
  {name: 'Albania', dialCode: '+355', countryCode: 'AL'},
  /* ... */
];
Enter fullscreen mode Exit fullscreen mode

So - do web components only accept strings? Poppycock! Balderdash! Flimshaw! The full expressive power of the DOM is available to your custom elements from day one.

Myth: Busted

And if you think you're limited to using the bare DOM APIs to set those properties... think again!

Myth: Web Components Have No Way Of Templating

Like the previous myth, this misconception has one foot in the truth. The most widely adopted web component spec is the <template> element, used for efficient static templating, and it's available across all evergreen browsers. The type of templating I want to talk about in this post uses what you might call "dynamic templates" or templates with variable parts.

<template id="person-template">
  <figure>
    <img alt="{{picture.alt}}" src="{{picture.src}}"/>
    <figcaption>{{name}}</figcaption>
  </figure>
</template>
Enter fullscreen mode Exit fullscreen mode

We'll start by discussing some proposed features, then show some examples you can run today.

Template Instantiation is a proposed web components spec that offers a future means to define DOM templates with slots for dynamic content. It will hopefully soon let us write declarative templates for our custom elements. The following maquette illustrates how that might look in practice:

<template type="with-for-each" id="list">
  <ul>
    {{foreach items}}
      <li class={{ type }} data-value={{value}}>{{label}}</li>
    {{/foreach}}
  </ul>
</template>

<script>
const list = document.getElementById('list');

customElements.define('awesome-web-components', class extends HTMLElement {
  #items = [
    { type: 'description', value: 'awesome', label: "Awesome!!" },
    { type: 'technology', value: 'web-components', label: "Web Components!!" }
  ];

  template = list.createInstance({ items: this.#items });

  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.appendChild(this.template);
  }

  set items(items) {
    this.#items = items;
    this.template.update(items);
  }

  get items() {
    return this.#items;
  }
});
</script>
Enter fullscreen mode Exit fullscreen mode
Note, I'm purposefully handwaving over the implementation of with-for-each here. This example is only to whet the appetite. See the proposal for more.

Template Instantiation will be hella-useful when it lands, but at the moment, we need to rely on libraries.

Does that mean that web components have no way of templating? Preposterous! There are a variety of approaches and libraries available, from lit-html, HyperHTML, or hybrids; to slim.js or svelte, and more.

A few examples to illustrate the point:

Templating with lit-html

import { LitElement, html } from 'lit-element';

const itemTemplate = ({ value, label, type }) => html`
  <li class=${type} data-value=${value}>${label}</li>`

customElements.define('awesome-web-components', class extends LitElement {
  items = [/* ... */]
  render() {
    return html`<ul>${items.map(itemTemplate)}</ul>`;
  }
});
Enter fullscreen mode Exit fullscreen mode

Templating with hybrids

import { define, html } from 'hybrids';

const itemTemplate = ({ value, label, type }) => html`
  <li class=${type} data-value=${value}>${label}</li>`;

define('awesome-web-components', {
  items: { get: () => [/*...*/] },
  render: ({ items }) => html`<ul>${items.map(itemTemplate)}</ul>`
});
Enter fullscreen mode Exit fullscreen mode

Templating with Slim.js

import { Slim } from 'slim-js';
import { tag, template } from 'slim-js/Decorators';
import 'slim-js/directives/repeat.js'

@tag('awesome-web-components')
@template(`
<ul>
  <li s:repeat="items as item"
      bind:class="item.type"
      bind:data-value="item.value">
    {{ item.label }}
  </li>
</ul>`)
class MyTag extends Slim {
  onBeforeCreated() {
    this.items = [/*...*/]
  }
}
Enter fullscreen mode Exit fullscreen mode

Templating with Svelte

<ul>
  {#each items as item}
    <li class="{item.type}" data-value="{item.value}">{item.label}</li>
  {/each}
</ul>

<script>
  export default {
    data() {
      return {
        items: [/*...*/]
      }
    }
  }
</script>
Enter fullscreen mode Exit fullscreen mode

It's worth mentioning at this point that some of these examples illustrate approaches that use build-time transpilation to render your templates (svelte in particular). But you aren't limited to that; hybrids, lit-element, and others run dynamic templates in the browser. You could paste the lit-element example (with some small modifications to resolve bare module specifiers) into the browser console and it would work.

With many of the various templating methods, you can also declaratively pass complex data as properties:

import { html } from 'lit-html';
const propPassingTemplate = html`
  <takes-complex .data=${{ like: { aTotal: ['boss'] } }}></takes-complex>`;
Enter fullscreen mode Exit fullscreen mode

So, can you write dynamic, declarative templates? Web components offer a straightforward templating story, without the hard requirement of a transpilation step. Moreover, there are plenty of different opinionated approaches in the ecosystem with more appearing as these standards gain notoriety.

Myth: Busted

Myth: Web Components Can't be Server-Side-Rendered

Server-side rendering is a technique whereby client-side javascript (or something like it) is executed on the server when a request comes in, generating an initial response containing content that would otherwise be unavailable until the aforementioned client-side code was downloaded, parsed, and executed. There are, generally speaking, two reasons why you would implement server-side rendering:

  1. To make your app's pages indexable by search engines that might not run JavaScript
  2. To reduce the time to first contentful paint

Can you accomplish these goals in a web-components app? Indubitably.

You can use Google's puppeteer (which runs headless Chrome or Firefox on your server) to render the contents of your components for the sake of web crawlers. The inimitable captaincodeman has a fully-realized example of SSR-for-SEO written in Go.

So there are ways to run your custom elements-based client side JS on the server for SEO purposes. What about reducing load times?

Well, it seems that the jury is out regarding whether or not running your templates server-side is faster in the first place. If the goal is to reduce FCP times, you might instead opt to calculate your data at request time, while factoring your client-side app with a lightweight static app shell. In this flavour of SSR, you have some server-side code which computes an initial state, à la this example from an Apollo Elements GraphQL app:

async function ssr(file, client) {
  // Instantiate a version of the client-side JS on the server.
  const cache = new InMemoryCache();
  const link = new SchemaLink({ schema: server.schema, context });
  const client = new ApolloClient({ cache, link, ssrMode: true });

  // Calculate the initial app state.
  await client.query({ query: initialQuery });
  const serializedState = JSON.stringify(client.extract());

  // Inject said state into the app with a static `<script>` tag
  const dom = await JSDOM.fromFile(file);
  const script = dom.window.document.createElement('script');
        script.innerHTML =
          `window.__APOLLO_STATE__ = ${serializedState}`;

  dom.window.document.head.append(script);

  // Send the modified index.html to the client
  return dom.serialize();
}

app.get(/^(?!.*(\.)|(graphi?ql).*)/, async function sendSPA(req, res) {

  // SSR All the Things
  const index = path.resolve('public', 'index.html');
  const body = await ssr(index, client);

  // 👯‍♀️👯‍♂️
  res.send(body);
});
Enter fullscreen mode Exit fullscreen mode

Doing the same for a different state container like redux is left as an exercise for the reader. (or, like... google it)

You'll note that none of this code is specific to web components or any specific templating library. When your components upgrade and connect to their state container, they'll get their properties and render according to whatever the implementation.

There's a lot more to say on this issue, and the story will only improve in the near term, as the lit-html team have prioritized work on SSR for 2019. I don't mind telling you, dear reader, that I'm not an expert. Give Trey Shugart, Kevin P Schaaf, and Justin Fagnani a follow if you want the low-down.

So, can you SSR all the things in your web components app? Well, don't expect any turn-key solutions here. It's early days, and the cowpaths are still quite fresh. Nonetheless, basic facilities are in use in production today, and there's a lot to look forward to coming up soon. But is it possible? Sure!

tl;dr: the techniques and libraries are still very early, but it's certainly possible to accomplish the goals of SSR in wc-based apps.

All right, I'm calling it.

Myth: Busted

Myth: Web Components are a Proprietary Google Technology

While the modern web components story began at Google (at a secret seance in the basement of one of their datacenters, I'm told 👻), it's grown beyond the bounds of any one company.

To wit:

Web Components specs are open standards with multiple implementations and stakeholders.

Myth: Busted

Myth: You Need Polymer to Use Web Components

This is a fun one. Back in the dark ages of 2013, the only way to use 'web components' was to use the polymer library, which back then functioned as a combination polyfill/templating system/build tool/package manager/kitchen sink. The reason for this was simple: The Polymer Project invented the modern notion of web components, and the Polymer library (version 0) was their prototype implementation.

Since then, things have changed drastically. The polyfills split off from the Polymer library and its opinionated templating system years ago, and are now in use by many independent projects.

If this is news to you, give a quick read to the first part of my Polymer Library post, which clarifies the difference between the Polymer Project and the Polymer Library.

So, no, you don't need Polymer to use web components. You don't even need the Polyfills if you're only supporting evergreen browsers (minus Edge until Edgeium ships)

Want proof? Open a new tab in Chrome, Firefox, or Safari and paste this snippet into the console:

customElements.define('the-proof', class extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      <style>:host { display: block; }</style>
      You just used web components without Polymer
    `;
  }
});

document.body.innerHTML = `
  <the-proof>You Can't use web components without Polymer!!</the-proof>
`;
Enter fullscreen mode Exit fullscreen mode

tl;dr: The polyfills are independent, and the Polymer project even recommends not using the Polymer library for new projects.

Myth: Busted

Myth: You Need to Use HTML Imports

One of the things that drew me in to web components back in 2015 was the notion of writing sophisticated components in HTML files. The now-defunct HTML Imports specification let us do just that, and here's how it looked:

<link rel="import" href="/my-component.html">
<my-component></my-component>
Enter fullscreen mode Exit fullscreen mode

HTML Imports struck a chord with many developers, as it signalled a return to a document-centric approach to web development, as opposed to the 'modern', script-centric approach, to which many of us find ourselves obliged nowadays. That's why, for many of us in the web components community, it was bittersweet when the HTML Imports specification was deprecated in favour of modules.

Yup, you read that right. HTML Imports are not a thing.1

Nowadays, web component and app authors are most likely to use JavaScript modules to package and import their components:

<script type="module" src="/my-component.js"></script>
<my-component></my-component>
Enter fullscreen mode Exit fullscreen mode

This approach opens the door to the huge assortment of tooling options we have out there, and means you don't need to use Polymer tools for your projects.

But you're not limited to modules either: <good-map> is a vanilla web component wrapper for Google Maps which is distributed as a script instead of as a module. If you visit that repo, and I hope you do, don't be alarmed by the (optional) legacy HTML import, or by the fact that the last update was two years ago, the web components specs mean it still works just fine.

tl;dr: Not only are HTML Imports unnecessary, but you actually shouldn't use them in your projects.

Myth: Busted

Myth: You Need to Use Shadow DOM

This is one of the easiest myths to bust. Used GitHub lately? You've used web components without Shadow DOM. Open a tab to https://github.com in your favourite evergreen browser and paste this snippet in the console:

const isCustomElement = ({ tagName }) => tagName.includes('-');
const usesShadowDom = ({ shadowRoot }) => !!shadowRoot;
const allElements = Array.from(document.querySelectorAll('*'))
console.log("All Custom Elements", allElements.filter(isCustomElement));
console.log("Uses Shadow Dom", allElements.filter(usesShadowDom));
Enter fullscreen mode Exit fullscreen mode

Shadow DOM is the secret sauce of web components and I highly recommend you use it to the fullest extent. However, there are times when you might not want to encapsulate all of a component's styles against the rest of the document2. For those instances, it's simple to avoid the use of Shadow DOM - just don't opt in!

Here's a simple copypastable example:

customElements.define('without-shadow', class extends HTMLElement {
  constructor() {
    super();
    // no call to `this.attachShadow`
    this.innerHTML = `<p>A Custom Element Without Shadow DOM</p>`
    this.style.color = 'rebeccapurple';
  }
});

document.body.innerHTML = `<without-shadow></without-shadow>`;
Enter fullscreen mode Exit fullscreen mode

So, while I think you should use Shadow DOM, it's nice to know that you don't have to.

Myth: Busted

Myth: You Need Frameworks to Write Apps

You might have heard tell that "web components are great for leaf nodes like buttons, but you need frameworks to build real apps" or some such argument. It's certainly the case that if you're building a leaf node like a checkbox or a card, web components are the hands-down favourite (see next myth), but what you might not know is that you can indeed build entire apps with them.

I built a demo app using Apollo GraphQL and web components that scores well in lighthouse. Then there's the pwa-starter-kit example app. It uses web components with redux3 to manage state, has client-side routing, integration tests, and all that app-y goodness. At Forter, we're building prototypes and internal apps without frameworks, and the results so far are very positive.

And there are many more examples. (Ever wonder which JS framework GitHub uses?)

Now, I happen to think it's just as wrong-headed to say you should never use frameworks as it is to say that you always need one. There's nothing inherently wrong with frameworks. A Framework might be the right choice for your project, but don't let anyone ever tell you that you need one to write web apps.

tl;dr: Frameworks are great, but they're not absolute requirements, even for cutting edge workflows.

Myth: Busted

Myth: You Can't Use Web Components in Frameworks

This one's a quicky. All it takes to dispel it is 10 seconds scrolling through https://custom-elements-everywhere.com

Even the frameworks with the worst custom elements support are slowly but surely working on improving the situation, and workarounds are available.

tl;dr: Web components 💓love💓 frameworks.

Myth: Busted

Myth: The Web Community Has Moved on From Web Components

If you've read the whole post up till now, you might be scratching your head thinking "isn't this obvious?" And yet, judging by the amount of internet noise claiming that WC is dead, it bears some fleshing out.

Mark Twain reclining with a Pipe. Caption reads: "Reports of my Death Have Been Greatly Exaggerated"

We've already seen how organizations large and small are shipping web components. We've seen how you yourself probably used web components on popular websites within the last hour. We've seen how >10% of page loads across all browsing sessions load a page with a custom element in it. And all of that is just the beginning.

In 2018, there was a veritable Cambrian Explosion of new ideas and shipped code in the web components world - from Firefox shipping full support in version 63 to Edge announcing intent-to-ship, to innovative library releases like hybrids and haunted (think React hooks for web components), to projects like Angular Elements which improve the already formidable interop story between elements and frameworks. We're not talking about browser-implementers pontificating from behind their compilers! As we've seen above, there's been tremendous adoption from developers themselves at companies large and small, and among community volunteers.

So what should we make of the sometimes-insistent voices who claim that "web components just aren't there yet?"

Domestic Cat Wearing a Lion Mane. Caption: "I'm a Lion Roar!!!!!!!"

Myth: Busted

Conclusion

If you've been waiting for web components to "arrive" before trying your hand at them, I'm giving you permission right now. It's an exciting time to be a web developer, and the future is only looking brighter.

Web components let us write and publish reusable pieces of web content and compose modular apps with increasingly small dependency and tool chains. If you haven't given this refreshing style of development a try, I hope you will soon.

Acknowledgements

Many people helped me write this post, and I'm very grateful.

Thanks in no particular order for generously offering their notes on this post go to westbrook, Dzintars, stramel, Thomas, tpluscode, and Corey Farell on the Polymer Slack; as well as lars, Passle, and daKmoR from the open-wc team; Dan Luria (who described this post as a 'brunch cocktail - both delightful and progressively more challenging') on the WeAllJS slack; my good friend Justin Kaufman; and my dear wife Rachel.

Endnotes

  1. Stay tuned, because the days of writing HTML-in-HTML are returning with the HTML Modules Proposal. back
  2. Most of the time, you'll want to use the <slot> element for this use case. The zero-shadow-DOM approach is best suited when, for whatever reason, you find your project unable to make use of the shadow DOM polyfill. back
  3. Don't like Redux or Apollo? Use a different (MobX, et al.), or no (mediator or meiosis patterns) state container - you have options. back

Top comments (49)

Collapse
 
qm3ster profile image
Mihail Malo

I understand why we can write web components. But why should we?
Are they currently faster?

Collapse
 
bennypowers profile image
Benny Powers 🇮🇱🇨🇦

You might have lots of motivations to use web APIs

  • Interoperability
  • Performance (both load and runtime)
  • Standardization
  • Vendor lock
  • You like the specific sugar offered by XYZ web components library or base class

Give this podcast a listen, they covered most of the major talking points.

pca.st/qY78

Collapse
 
wannesdebacker profile image
Comment marked as low quality/non-constructive by the community. View Code of Conduct
Wannes De Backer • Edited

None at all.

There is NO w3c spec, there is no stability. This article is bullshit.

Collapse
 
bennypowers profile image
Benny Powers 🇮🇱🇨🇦

I really don't appreciate your language and personal insults.

Thread Thread
 
wannesdebacker profile image
Wannes De Backer

There, i fixed it (i shouldn't have attacked you in person but i'm still super-triggered by this article, obviously i don't know your skills and therefore i can't be sure).

But i really don't appreciate you ignoring the w3c, inspiring other to do the same and basically lying about some points. Also reading the comments here is really eyeopening how backwards the current state of the web is, with companies trying to impose standards, people ignoring w3c. I can't stress enough how wrong and even dangerous this is.

Thread Thread
 
westbrook profile image
Westbrook Johnson
Thread Thread
 
wannesdebacker profile image
Wannes De Backer

proposal...

Thread Thread
 
westbrook profile image
Westbrook Johnson

specs, for the baseline, requisite parts of deploying web components today, and Proposals, for a lot of great future possibilities that are important to discuss as a community right now so our voices can be heard in the process, it's kind of how the w3c does its thing... It's a pretty beautiful process, even if its speed can leave you wanting at times. 😉Have you taken part in it before?

Thread Thread
 
wannesdebacker profile image
Wannes De Backer

That is my point, but there is a big difference between discuss possibilities in the community and just saying: It's ready, just use it. And claiming that it is stable when it is totally not.

Thread Thread
 
qm3ster profile image
Mihail Malo

Companies are using it. That's what drives the browsers.
There are stats in the post.

Thread Thread
 
westbrook profile image
Westbrook Johnson

Other than the Template Instantiation proposal, which of the technologies above aren't in the specs folder of that repo? Beyond that (which is noted very clearly as a proposal) everything else is 100% ready, as outlined in the article. What's more, discussion of the Template Instantiation proposal, and the benefits that will bring are have in the context of a production ready libraries that do similar work and specifically one that builds on the capabilities of the spec in anticipation of its arrival due to strong support across browser vendors and the developer community.

 
wannesdebacker profile image
Wannes De Backer

That is never a reason, and browsers should implement what w3c envisions, not the other way around.

Thread Thread
 
westbrook profile image
Westbrook Johnson

Can you confirm for me what you think a proposal is?

It has been my understanding that the w3c doesn't make those internally, the community does. It just so happens in this case that some of the proposals came from the Chrome team at Google which had been spending a lot of time with devs and found some valuable additions to be made to the platform. In that case of Template Instantiation it comes predominately from Apple. In the case of HTML Modules, Microsoft.

Is the w3c not a consortium on many vested parties that together come up with the future of the web? You speak as the web we all work with is laid down as dogma from some shadow group.

Thread Thread
 
qm3ster profile image
Mihail Malo

Are you seriously suggesting browsers shouldn't focus on implementing anything and everything that is being massively polyfilled in the wild?

Thread Thread
 
tjmonsi profile image
Toni-Jan Keith Monserrat

When you understand that the w3c's protocols on creating and establishing those standards would always start with a proposal that would need data (like how many like this implementation and how many people/devs/companies are implementing this proposed spec) to back up the claim that this spec is the way forward... then you'll understand that the web standard will always start at these proposals.

Besides, these proposals has phases.

"Browsers should implement what w3c envisions..." <- I think what w3c envisions always start in those proposals... and technically, they are already doing it.

Collapse
 
bennypowers profile image
Benny Powers 🇮🇱🇨🇦

I hate to reopen old wounds, but for the sake of those future readers who stumble upon this thread and think that there's still merit to Mr. De Backer's comments, I feel it's necessary to point out that all of the web components standards are in fact part of the W3C specification

Moreover, the W3C has in fact ceded control of the HTML and DOM specifications to the WHATWG, in effect retroactively ratifying the specs above mentioned.

All of the links in this comment are to w3.org

Now get out there and be awesome, everyone!

Thread Thread
 
wannesdebacker profile image
Wannes De Backer

All unusable, will not work on Internet Explorer.

Thread Thread
 
bennypowers profile image
Benny Powers 🇮🇱🇨🇦

I'm responding here to spectators, because of course Mr. De Backer already knows that polyfills enable support down to IE11.

So, in fact you can write web components that work in ie11.

However, that doesn't mean that you should.

Collapse
 
qm3ster profile image
Mihail Malo • Edited

Tag @bennypowers , you coward :D
Jk, but who cares about w3c? Implementation is all that matters.
Like, I wish tail call optimization was implemented, but it isn't?
So I'm obviously not going to use it?

Thread Thread
 
lirown profile image
Liron Goldenberg

I wouldn’t respond t someone that being disrespectful... keep that in mind when responding

Thread Thread
 
qm3ster profile image
Mihail Malo

Did you mean to respond to me or someone else?

Thread Thread
 
lirown profile image
Liron Goldenberg

meant to replay Wannes De Backer :X
Sorry Mihail.

Collapse
 
gugadev profile image
Gustavo Garsaky • Edited

Awesome and curated myth list, Benny! Currently, we are creating a design system in my company, but we are thinking in throw away using Web Components for a few but important reasons. Here are some of them.

1 - There is no way to access shadowed elements via CSS from outside (/deep/ and ::shadow selectors are deprecated and ::part is on draft yet). Yeah, this is a clear violation to the encapsulation principle, but, this is necessary in some cases. For example:

We have an <ck-icon> component. By default, it's color is dark gray (#333333). Theorically, this icon should inherit the color of the parent. Why? because, when it's inside an <ck-button> and the color is -for example- white, the icon should have the same color. Otherwise, the button will have a white color and the icon a gray one.

<!-- background: green; color: white -->
<ck-button kind="primary">
  <!-- color: gray; 😕 -->
  <ck-icon name="checkout"></ck-icon>
  <ck-text content="checkout"></ck-text>
</ck-button>
Enter fullscreen mode Exit fullscreen mode

2 - ShaddyCSS has some important limitations. For example, when using lit-element and want to apply styles from properties (using interpolation) it didn't works.

<style>
:host {
  ${importedStyles.toString()}
  <!-- property inside style tag is not reevaluated by Shaddy
       so, we can't override default styles -->
  ${this.props.color ? html`color: ${this.props.color}` : null }
}
</style>
Enter fullscreen mode Exit fullscreen mode

Note: this works fine on browsers with native support.

Collapse
 
bennypowers profile image
Benny Powers 🇮🇱🇨🇦 • Edited

Yes those are important considerations, and shadow parts will solve many of them. In the mean time, one approach would be to slot in elements you need to style from light DOM. Alternatively, expose lots of custom properties.

As for interpolated styles, CSS custom properties and the style attribute are the preferred route for now. I expect to see some nice patterns emerge as Constructable Style Sheets gain traction.

As mentioned, you could also take the approach of not using shadow DOM, but I think that would be a loss.

WRT color, inherited properties should pierce shadow boundaries, so this sounds like a bug. Repro?

Collapse
 
thatjoemoore profile image
Joseph Moore

I've solved both of these problems using CSS Properties.

In their stylesheets, ck-icon and ck-text would both use a custom property:

  color: var(--ck-text-color, #333333);

Then, in ck-button (and any other element that manipulates the background color):

:host[kind=primary] {
  --ck-text-color: white;
}

We've solved your second problem by side-stepping it whenever we can - when we use attributes (like your 'kind'), we set styles based on the attribute values, often in the form of a bundle of CSS properties that get used elsewhere in the stylesheet.

For more dynamically-computed styles, though, you are kind of stuck. The Shady DOM polyfill stamps out its template and styles once for each element (I think this is done for reasons of performance). One thing we did was call back to the ShadyDOM polyfill with a different element name (my-element-{hash of state}) for each state we encountered (though you should be careful, as this can easily backfire). Or, you can, as Benny said, just set styles directly on the element. It's maybe not the prettiest solution, but it works!

Thread Thread
 
westbrook profile image
Westbrook Johnson

Joseph, my-element-{hash of state} is a really slick work around to the dynamic styling issue. The idea of "re-defining" your custom element on demand like that is actually pretty central to the way Skatejs approaches elements and their define package could be seen as a pretty fleshed out helper to intersect the two concepts.

Thread Thread
 
thatjoemoore profile image
Joseph Moore

So, we don't actually redefine the entire element, we just define a new template for ShadyDOM to play with. The actual code is here. I wouldn't reuse it verbatim, as it makes some assumptions that are very specific to us (like that, 99% of the time, our theme elements don't change their template once they've been stamped out the first time, so we don't need to worry about advanced diffing and such). We're also using a slightly older version of the polyfill, so it's possible that ShadyDOM has some new features that would get rid of some of this code.

Collapse
 
westbrook profile image
Westbrook Johnson

I've gotten stung by your point about the icon colors inheriting before as well. If you use SVG based icons, maybe we've been running into it for the same reasons. When I've had the issue you outline it's been because I've forgotten to use currentColor in my SVG attributes. It's easy to get an SVG that looks great out of the box and push it directly into my project, but if the fill or stroke or color attributes have fixed colors in them they'll quickly clash with some insertion point in my project. If you were interested in sharing a little more details in regards to your ck-icon elements, I'm sure we would both have something to learn from each other!

Benny's point about making sure to use things like color: inherit;, etc. is also really important as between the use of these two techniques and possibly CSS Custom Properties if absolutely needed, you should be able to maintain full control over your icon delivery, regardless of the context.

Collapse
 
thatjoemoore profile image
Joseph Moore

Thanks for debunking these myths! I'm definitely keeping this around for the next time I run into these (an almost weekly occurrence).

My organization has been an early adopter of Web Components - we've had them in production for three years, and they've formed the core of our (wildly successful) design framework for two years. We keep running into these myths about them, but it's really fun to tell people that, if they're using the official theme, they're already using them and they just didn't realize it.

I wrote up some stuff about what we've been doing here, for those that are interested in what kinds of problems we tackled and how we dealt with them.

Collapse
 
dehuszar profile image
Samwise Gamgee

Can you provide an example of how you might pass complex data into a vanilla web-component via the HTML template?

I think the myth about web components not supporting complex data passing comes from folks having trouble doing React-style passing of props.

Collapse
 
bennypowers profile image
Benny Powers 🇮🇱🇨🇦 • Edited
import { html, render } from 'lit-html';

const hobbitTpl = ({name, ability}) => html`
  <dt>${name}</dt>
  <dd>${ability}</dd>`

customElements.define('muh-hobbits', class extends HTMLElement {
  set band(val) {
    this.__band = val;
    if (!Array.isArray(val)) return;
    // Would be a great place to use template Instantiation when it lands
    render(html`<dl>${val.map(hobbitTpl)}</dl>`, this.shadowRoot)
  }

  get band() { return this.__band; }

  constructor() {
    super();
    this.attachShadow({mode:"open"})
  }
});

const main = document.querySelector('main')
render(html`<muh-hobbits .band=${[
  {name: 'Frodo', ability: 'courage' },
  {name: 'Samwise', ability: 'loyalty'},
  {name: 'Pippin', ability: 'strength'}
]}></muh-hobbits>`, main)


But at this point you might as well extend from lit element. It's vanilla enough.

Collapse
 
dehuszar profile image
Samwise Gamgee

That's sorta what I was trying to get at though. Lit is a light framework, but it would be nice to see an example of how one passes in rich data to a string literal web component template using nothing but the core spec. I think part of the reason this myth persists is because there's not a clear explanation about how to do it without resorting to tooling.

I have tried a bunch of different ways, but can't get past the fact that attributes have to be strings, and there aren't clearly explained ways to otherwise pass complex data into the component.

The closest I've gotten is to just use the slot system and require each page-level template to visibly nest component, so that arrays, as in your example, can be mapped in such a way that values land in their intended sub-component attributes as strings.

Thread Thread
 
bennypowers profile image
Benny Powers 🇮🇱🇨🇦

🤷‍♂️

Web component specs are not meant to solve every high-level concern for every use case. They're low-level primitives.

Libraries (in contradistinction to frameworks) like lit-html etc are there to build on the specs to provide high level uses.

Future primitives like Template Instantiation will let libraries like those be even smaller and more efficient.

Thread Thread
 
westbrook profile image
Westbrook Johnson

This is a great point Samwise, there is a lot of ambiguity around this. I'm gonna show you one way that you can address this, but I'd be very interested in knowing whether you have a non-web component example of how this might be possible. Knowing what the explicit goals you might have is half the battle when it comes to architecting a useful solution. What I share below will be useful for some requirement, but likely not all, in this area.

In so far as you want a library free (except the polyfills) approach to passing rich data into a web component, I offer the following:

There are certainly things that could be said against this approach. In particular, the idea that JSON.parse() prevents the maintenance of identity is a big one. In response to that, I'd question how someone would actually rely on the idea of setting data as attributes beyond the initial load of a page. In that case, setting an initial identity that then can be maintained inside of the application by passing properties (theoretically you'd be in/have access to the JS scope at that point, so it would look like otherElement.customProperty = y) would absolve that issue.

What other use cases for communicating rich data between web components have you run into? I look forward to hearing about it! I think this is a really interesting part of the web components conversation, and techniques established and discovered in this area will benefit well beyond simply trying to set rich data on an element.

Collapse
 
konrud profile image
Konstantin Rouda

Nice write-up. I'd say that learning Web Components it's easier than learning any new Framework/Library.
I've even made a few myself.
Example: <switch-component></switch-component>

Collapse
 
eavichay profile image
Avichay Eyal

Well written. As a web-components evangelist I agree with everything you say.
I would mention Unit-Tests for web-components techniques.

You can read about my (working in production for several companies) tool here:
medium.com/.../easy-unit-tests-for...

Collapse
 
qm3ster profile image
Mihail Malo

some of these examples illustrate approaches that use build-time transpilation to render your templates (svelte in particular). But you aren't limited to that

That's not a limit, that's a superpower.

Collapse
 
rhymes profile image
rhymes

tl;dr: Web components 💓love💓 frameworks.

Especially Angular and Vue I see. React seems to be going in another direction...

Collapse
 
bennypowers profile image
Benny Powers 🇮🇱🇨🇦

Alas... Unrequited love...

Collapse
 
bennypowers profile image
Benny Powers 🇮🇱🇨🇦

footnote, preact has a much friendlier custom-elements support story

Collapse
 
allexon profile image
Alexon da Silva Moreira

Eu tinha tentando muito coisa, Vue, Angular, React, no primeiro momento parecia fantástico, mas quando você tentava utilizar puramente javascrip, tinha que me adaptar as regras de convenção destas ferramentas, quanto mais eu utilizavas estas ferramentas menos eu aprendia javascript, mas eu gostava da questão de componentização até conhecer web components e finamente chegar onde eu gosto, puro javascript eu crio as minhas regras o programador no controle novamente SHOW!!!! SHOW!!!! Muito Obrigado por este artigos, ainda ainda só estou dando uma passada , para estudar com calma cada linha!!!!!

Collapse
 
grandemayta profile image
Gabriel Mayta

Long live to Web Components!

Collapse
 
directspeaker profile image
directspeaker

A great wonderful read. I must appreciate the way you have presented here for easy understanding.
Thanks

Some comments may only be visible to logged-in visitors. Sign in to view all comments.