Remix.run Logo
crazygringo 18 hours ago

But there's no real reason to, and it just adds confusion around which elements are semantic -- bringing formatting, functionality, meaning to screen readers and search engines, etc. -- vs which are custom and therefore carry no semantic meaning.

If there's no native semantic tag that fits my purposes, I'd much rather stick to a div or span as appropriate, and identify it with one (or more) classes. That's what classes are for, and always have been for.

Support for custom HTML elements seems more appropriate for things like polyfills for actual official elements, or possibly more complicated things like UX widgets that really make sense conceptually as an interactive object, not just CSS formatting.

Using custom element names as a general practice to replace CSS classes for regular formatting just feels like it creates confusion rather than creating clarity.

yawaramin 18 hours ago | parent | next [-]

So, the article doesn't discuss this, but there's actually a really good reason to make up and use custom elements: the browser can hydrate their dynamic behaviour automatically. For example, suppose you have:

    <div class=expander>
      <button aria-expanded=false>Expand</button>
      <!-- Some other stuff here -->
    </div>
And you have some JS that handles the expander's behaviour:

    for (const expander of document.querySelectorAll('.expander')) {
      const btn = expander.querySelector('button');

      btn.addEventListener('click', () => {
        btn.ariaExpanded = 'true';
      });
    }
This will work fine for `.expander` divs that are already in the page when the event handler is set up. But suppose you dynamically load new expander divs, what then? Your event handler is not going to retroactively set up their click listeners too.

Custom elements solve exactly this problem. You can now do:

    <expander-elem>
      <button aria-expanded=false>Expand</button>
      <!-- Some other stuff here -->
    </expander-elem>
And then set up the listener:

    customElements.define('expander-elem', class extends HTMLElement {
      connectedCallback() {
        const btn = this.querySelector('button');

        btn.addEventListener('click', () => {
          btn.ariaExpanded = 'true';
        });
      }
    });
And the browser will ensure that it always sets up the listeners for all of the expanders, no matter whether they are loaded on the page initially or dynamically injected later. Without this you would have had to jump through a bunch of hoops to ensure it. This solves the problem elegantly.
dannye 14 hours ago | parent | next [-]

this.querySelector will return nothing when you define this Web Component before (light)DOM is parsed, because the connectedCallback fires on the opening tag.

Above code will only work when the Web Component is defined after DOM has parsed; using "defer" or "import" makes your JS file execute after DOM is parsed, you "fixed" the problem without understanding what happened.

I blogged about this long time ago: https://dev.to/dannyengelman/web-component-developers-do-not...

yawaramin 7 hours ago | parent [-]

Well, that's why I include JS files at the bottom of my HTML body, to make sure to avoid exactly this problem: https://github.com/yawaramin/dream-html-ui/blob/92f2dfc51b75...

crazygringo 8 hours ago | parent | prev | next [-]

That's good to know, and I even did say that custom UX widgets are a case where custom tag names makes more sense conceptually.

I'm really just pushing back on the idea of using them for CSS formatting purposes of general text and layout instead of classes.

rasso 17 hours ago | parent | prev | next [-]

Beware that connectedCallback runs _every time_ a custom element is added to the dom. So you should make sure to only add event listeners once by tracking internally if the element was already initialized.

kcrwfrd_ 16 hours ago | parent | prev [-]

Yes, the hydration behavior of custom elements is nice. You don’t even need to do anything special with JS bundle loading.

Simply render your <element> (server-side is fine) and whenever the JavaScript downloads and executes your custom elements will mount and do their thing.

veqq 16 hours ago | parent | prev | next [-]

> no real reason

Doing this for syntax highlighting on https://janetdocs.org/ shrank the homepage's .html from from 51kb to 24kb, or 8kb to 6kb compressed (at the time).

gitaarik 17 hours ago | parent | prev [-]

Why would it create confusion? Because you're not familiar with it? Things change..

crazygringo 8 hours ago | parent [-]

Because there are so many native elements to keep track of now.

If you see an unfamiliar tag that has a reasonably simple name, you simply don't know if it's native or for formatting.

That's confusing. It's taking two categories of things and mixing them so you can't tell them apart.

gitaarik 3 hours ago | parent [-]

There's a very clear rule for it: if it contains a dash it's a custom element

crazygringo 16 minutes ago | parent [-]

That rule doesn't work in reverse. If there's no dash it could be either.

So now you've got to try to enforce some practice of using hyphens in all tag names that used to be class names, even if they're a single word that has no place for a hyphen?

It's getting even more confusing now, you see? Not less.

Just use classes. That's what they're there for.