logoalt Hacker News

_bentonyesterday at 5:53 AM2 repliesview on HN

Im not sure what you're referring to, they seem pretty straightforward to me. Create a class that extends HTMLElement, implement stuff in connectedCallback and attributeChangedCallback. Return a list of attributes in static observedAttributes. Or use some extended class if you want, there are plenty and they're easy to create your own.


Replies

troupoyesterday at 9:58 AM

You mean other than the 20+ web specs they added to platform (often to "fix" problems that they themselves introduced and/or that no one else has)? https://w3c.github.io/webcomponents-cg/2022.html (this list appeared after half a dozen or more specs had already been rammed through)

Or that their mere existence infects nearly every spec in existence delaying and needlessly complicating actual useful specs like Scoped CSS?

show 1 reply
JimDabellyesterday at 3:24 PM

Let’s take this example:

    <!DOCTYPE html>
    <title>Example</title>
    <cool-dog>
        <template shadowrootmode="open">
            <style>
                :host {
                    display: block;
                    font-family: system-ui;
                    margin: auto;
                    width: fit-content;
                }
                ::slotted(img) {
                    border-radius: 1em;
                }
            </style>
            <slot></slot>
        </template>
        <img
            src="https://placedog.net/512/342?random"
            width="512"
            height="342"
            alt="A dog"
        >
        <p>Check out this cool dog!</p>
    </cool-dog>
    <script>
        customElements.define(
            "cool-dog",
            class extends HTMLElement {},
        );
    </script>
First off, what’s with the pointless JavaScript? There’s no need for imperative code here. All web components have a dash in the name; this can be inferred. But even if you want it to be explicit, this could be done with markup not imperative code. But no, it doesn’t work without the pointless JavaScript ritual.

Now, I’ve noticed that since the text is a caption for the image, I should actually use <figure> and <figcaption>. So let’s do that:

    <!DOCTYPE html>
    <title>Example</title>
    <cool-dog>
        <template shadowrootmode="open">
            <style>
                :host {
                    display: block;
                    font-family: system-ui;
                    margin: auto;
                    width: fit-content;
                }
                ::slotted(img) {
                    border-radius: 1em;
                }
            </style>
            <slot></slot>
        </template>
        <figure>
            <img
                src="https://placedog.net/512/342?random"
                width="512"
                height="342"
                alt="A dog"
            >
            <figcaption>Check out this cool dog!</figcaption>
        </figure>
    </cool-dog>
    <script>
        customElements.define(
            "cool-dog",
            class extends HTMLElement {},
        );
    </script>
Wait a sec! The nice round corners on the image have turned into ugly square ones. Why is that?

It’s because web components can’t style anything other than their direct children. You can style the <img> when it’s a direct child of the web component, but as soon as you need anything more complex than an entirely flat hierarchy, you run into problems. Even if it’s something as simple as wrapping an <img> in a <figure> to associate it with a <figcaption>.

What’s the “official” way of getting things like this done when you bring it up with the people working on the specs? Make a custom property to fake the real one and then set a global style that listens to the fake property to set it on the real one:

    <!DOCTYPE html>
    <title>Example</title>
    <style>
        img {
            border-radius: var(--border-radius);
        }
    </style>
    <cool-dog>
        <template shadowrootmode="open">
            <style>
                :host {
                    display: block;
                    font-family: system-ui;
                    margin: auto;
                    width: fit-content;
                    --border-radius: 1em;
                }
            </style>
            <slot></slot>
        </template>
        <figure>
            <img
                src="https://placedog.net/512/342?random"
                width="512"
                height="342"
                alt="A dog"
            >
            <figcaption>Check out this cool dog!</figcaption>
        </figure>
    </cool-dog>
    <script>
        customElements.define(
            "cool-dog",
            class extends HTMLElement {},
        );
    </script>
Now let’s say I want to put a second <cool-dog> element on the page. What does that look like? You define the template once and then just use <cool-dog> a bunch of times? That would be the obvious thing to do, right? Since it’s a template?

Nope. Every instance of the web component needs its own <template>. The best you can do is write some JavaScript to copy the template into each one.

The developer ergonomics of this stuff is terrible. It’s full of weird limitations and footguns.

show 1 reply