Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

lit-element getElementById in connectedCallback returns null

I remember many web components tutorials say connectedCallback is good for hooking up DOM events or getting some DOM elements (like this one). But I couldn't get a simple program to run in lit-element:

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

class MyElement extends LitElement {
  render() {
    return html`<p id="root">template content</p>`;
  }

  connectedCallback() {
    super.connectedCallback();
    this.shadowRoot.getElementById('root'); // null
  }

  firstUpdated() {
    this.shadowRoot.getElementById('root'); // not null
  }
}

Looks like it only works in firstUpdated, doesn't firstUpdate fire after first render? what if I need some events set up before first render? why connectedCallback doesn't work here?

like image 640
Hammerhead Avatar asked Jul 31 '26 00:07

Hammerhead


1 Answers

connectedCallback works according to the spec, it just doesn't do what you expect.

Those callbacks fire at different moments in time

<my-element myattribute="foo">   1. -> connectedCallback
  <p id="root">
    template content
  </p>
</my-element>  2. -> firstUpdated (LitElement)

1. -> connectedCallback means the Element is injected in the DOM. but its children are not parsed yet.

Unless you use a FireFox (pre 2021 version!!), which fires connectedCallback too late at 2. (confirmed bug)

Think of elements as water hoses; connect means the hose is connected to a tap, not that water flows through it. So you can access data-attributes (a property of the hose) in the connectedCallback

That is why the connectedCallback fires at this 1. -> moment in time... you may want content based on its attributes. And you don't want to wait for all content to be parsed (which potentially can be a very very large DOM tree)

Also note connectedCallback runs every time you move the Element in the DOM

And if you dive deeper you will also notice attributeChangedCallback runs before the connectedCallback if you have observerAttributes on your element.

LitElement lifecycle callbacks are sugar, they 'safeguard' you against (powerful) bare metal Web Component behaviour.

So without LitElement, you can do:

connectedCallback(){
  // 1. -> do stuff
  setTimeout(() => {//no tricks, just wait till that dreaded JS Event Loop is done
    // all children are parsed
    // 2. -> do stuff
  });
}

For gory callback details see: wait for Element Upgrade in connectedCallback: FireFox and Chromium differences

like image 73
Danny '365CSI' Engelman Avatar answered Aug 01 '26 19:08

Danny '365CSI' Engelman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!