Custom Web Components, Part 2

Custom Web Components, Part 2

In my last article, Custom Web Components, Part 1, I discussed how one did not necessarily need JavaScript code to make use of custom parts of the Web Components system for better wrangling of HTML and CSS.

But that's obviously not the point of Web Components. Web Components are meant to encapsulate and share more advanced functionality than fancy DIV tags with drop shadows.

So, what does a basic Web Component look like? The absolute minimum amount of code necessary to define a custom tag is:

class MyElement extends HTMLElement {
}

customElements.define("my-element", MyElement);        

Okay, okay. That wasn't fair. What is the bare minimum amount to be able to functionally do anything?

class MyElement extends HTMLElement {    
    constructor() {
        super();
    }

    static observedAttributes = [
        // e.g. "disabled", or "mywholenewattributename"
    ];

    attributeChangedCallback(name: string, oldValue, string, newValue: string) {
    }

    connectedCallback() {
    }

    disconnectedCallback() {
    }
}

customElements.define("my-element", MyElement);        

Some notes here:

  • Only ever extend the basic HTMLElement, or other element types that you create. Don't extend any of the built-in elements. It's supported in Chrome and Firefox (mostly), but it's not supported in Safari and won't ever be. Apple is demanding a rethink to how customized built-in elements work. Which sucks for us trying to get things done. But it's also good, because the current implementation does indeed suck.
  • If you want to create a customization of, say, HTMLSelectElement, it's still possible by using composition instead of inheritance. Don't forget that, in TypeScript, classes can implement anything as an interface, even other classes. So, you could have MyElement implement HTMLSelectElement, then use an interior <select> tag to forward calls for the interface implementation.
  • The constructor must be a parameterless constructor. When you go to create an instance of your element, you will call document.createElement("my-element"); which does not provide any facility to provide parameters to the constructor. It's okay if intermediate classes in the middle of an inheritance hierarchy take parameters that get passed by the child classes, but the ultimate leaf of that tree needs to have a parameterless constructor.
  • You cannot add child elements to the element or change attribute values in the constructor. You can set event handlers. You can also create and set fields or properties in the element, just as long as they don't involve calling one of the (set/get/toggle)Attribute methods. You must wait until the constructor has finished before the children or attributes of the element can be changed.
  • Only the attributes listed in the static observedAttributes array will be reported by attributeChangedCallback.
  • I'll often stick "if(oldValue === newValue) return;" at the top of all of my attributeChangedCallback's to bomb-out early, because attributeChangedCallback will fire for every call of setAttribute, regardless of whether it had actually changed.
  • The connectedCallback and disconnectedCallback are called when the element is first inserted into/removed from a document tree. It's not whenever the element is added to another element. That other element could itself not yet be in the document tree. It's only when the element is added to another element that is already in the document.
  • Most of the time, I have some internal changes to the element that I want to make, anything that involves modifying the children or attributes of the element. Often, connectedCallback is the best time to do that. It's not the only time, or the earliest time, but it's certainly the last time you can change the structure of the element before anyone will see it. It's easy to listen for and you can reliably capture it.
  • But sometimes, connectedCallback is not the best, because it can actually be called multiple times: once for every time the element is added into the document, if it had gotten removed at any point. Sometimes, I find it best to undo in disconnectedCallback whatever changes I did in connectedCallback. Sometimes, I find it best to have some kind of logic to make sure the code I'm running in connectedCallback happens only once (e.g. a this.isFirstTime flag that is set to true in the constructor, then false at the end of connectedCallback).

These are the basics. You could get started from just this. You should get started from just this. You should play around with these features and then, when I have the next article ready, you'll have lived experience with some difficult warts that I will cover how to handle in the next article.

要查看或添加评论,请登录

Sean McBeth的更多文章

  • Custom Web Components, Part 1

    Custom Web Components, Part 1

    Custom Web Components are a set of Web browser technologies that allow Web application developers to essentially create…

  • The Trouble with Free Software

    The Trouble with Free Software

    To start, let me say that I believe in Free (libre) Software, as it is defined by the Software Freedoms. People should…

  • Windows Mixed Reality Headset from HP

    Windows Mixed Reality Headset from HP

    So this box showed up on my door step a few days ago. Not that it was a surprise, I've had the thing on order for…

    6 条评论
  • Primrose WebVR Framework v0.31.1 Released

    Primrose WebVR Framework v0.31.1 Released

    I made a release for v0.31.

    1 条评论
  • Primrose WebVR Framework v0.31.0 Released

    Primrose WebVR Framework v0.31.0 Released

    Over the last year, a lot of work went into making the Primrose WebVR framework much more reliable, easier to use, and…

    1 条评论
  • What is Primrose VR vs. what is Primrose LLC?

    What is Primrose VR vs. what is Primrose LLC?

    I have been building this software project for a little over a year now. I call it Primrose.

    1 条评论
  • Funding for Primrose

    Funding for Primrose

    I think it needs to happen soon. Either a Kickstarter or private seed funding of some kind.

    1 条评论
  • I just hacked my brain

    I just hacked my brain

    I think, when you start experimenting on yourself, you officially upgrade to actual, real-life mad scientist, not just…

    11 条评论
  • "Looking for technical co-founder, but nobody will work for free."

    "Looking for technical co-founder, but nobody will work for free."

    I see this on the entrepreneurial-bent message boards across the internet. A guy in a suit comes on and complains they…

    5 条评论
  • Confession: I Quit Relgious Unit Testing

    Confession: I Quit Relgious Unit Testing

    I used to be very devout in the ways of Unit Testing and Test Driven Development, even proselytizing to other…

社区洞察

其他会员也浏览了