Concorde documentation (crawl) · interactive version

Concorde decorator — @awaitConnectedAncestors and @dispatchConnectedEvent. The @awaitConnectedAncestors and @dispatchConnectedEvent decorators delay a web component's initialization until its matching ancestors have executed their connectedCallback. This is when contextual e Doc ID: docs/_decorators/wait-for-ancestors. Keywords: Concorde, supersoniks, docs/_decorators/wait-for-ancestors, wait-for-ancestors, @awaitConnectedAncestors and @dispatchConnectedEvent, decorator, awaitConnectedAncestors and @dispatchConnectedEvent, @awaitConnectedAncestors, @dispatchConnectedEvent, connectedCallback, sonic-connected, @dispatchConnectedEvent(). URL: https://concorde.supersoniks.org/crawl/docs/_decorators/wait-for-ancestors.html.

@awaitConnectedAncestors and @dispatchConnectedEvent

The @awaitConnectedAncestors and @dispatchConnectedEvent decorators delay a web component's initialization until its matching ancestors have executed their connectedCallback. This is when contextual elements (publisher, dataProvider, etc.) are configured.

Principle

When a child component attaches to the DOM, its ancestors may not yet be initialized (especially if custom element definitions are loaded asynchronously). The @awaitConnectedAncestors decorator delays the component's connectedCallback until all ancestors matching the provided CSS selectors have executed their connectedCallback.

The @dispatchConnectedEvent decorator allows ancestors to signal they are ready by dispatching the sonic-connected event at the end of their connectedCallback. The event bubbles, so it can be listened to from anywhere (e.g. document.addEventListener(CONNECTED, handler)).

Ancestors that are not web components (no hyphen in tag name) are considered connected by default and do not need to emit the event.

Usage

Import

import { awaitConnectedAncestors, dispatchConnectedEvent, ancestorAttribute } from "@supersoniks/concorde/decorators";

Basic example

An ancestor container decorated with @dispatchConnectedEvent() signals when it is ready. A child component decorated with @awaitConnectedAncestors("demo-wait-ancestor-container[dataProvider]") waits for this container to be initialized before initializing itself. Parameters are CSS selectors (element.matches()).

The parent is registered via customElements.define() (vanilla JS) rather than @customElement, so it can be defined later—e.g. when the user clicks a button. This demonstrates the child waiting until the parent exists.

import { html, LitElement } from "lit";
import { customElement, state } from "lit/decorators.js";

// Parent: registered later via customElements.define(), not @customElement
@dispatchConnectedEvent()
export class DemoWaitAncestorContainer extends LitElement {
  render() {
    return html`<slot></slot>`;
  }
}

// Child: waits for parent before initializing
@customElement("demo-wait-ancestor-value")
@awaitConnectedAncestors("demo-wait-ancestor-container[dataProvider]")
export class DemoWaitAncestorValue extends LitElement {
  @ancestorAttribute("dataProvider")
  dataProvider: string | null = null;

  @state() initializedAt: string = "";

  connectedCallback() {
    super.connectedCallback();
    this.initializedAt = new Date().toISOString();
  }

  render() {
    return html`
      <p>DataProvider from ancestor: <strong>${this.dataProvider || "—"}</strong></p>
      <p>Initialized at: ${this.initializedAt || "(waiting for parent…)"}</p>
    `;
  }
}

// Demo section: register parent via customElements.define() when user clicks
@customElement("demo-wait-ancestors-section")
export class DemoWaitAncestorsSection extends LitElement {
  registerParent() {
    if (!customElements.get("demo-wait-ancestor-container")) {
      customElements.define("demo-wait-ancestor-container", DemoWaitAncestorContainer);
    }
  }
  render() {
    return html`
      <sonic-button @click=${this.registerParent}>Register parent component</sonic-button>
      <demo-wait-ancestor-container dataProvider="waitAncestorDemo">
        <demo-wait-ancestor-value></demo-wait-ancestor-value>
      </demo-wait-ancestor-container>
    `;
  }
}
<docs-demo-sources for="demo-wait-ancestors-section"></docs-demo-sources>
    <demo-wait-ancestors-section></demo-wait-ancestors-section>

Multiple ancestors

The child waits for all specified ancestors. Register outer first, then inner — the child initializes only when both are ready.

<demo-wait-ancestors-multi-section></demo-wait-ancestors-multi-section>

Ancestors already connected

When the parent is defined at load and already in the DOM, the child initializes immediately (no delay).

Static (both in DOM from start):

<docs-demo-sources for="demo-wait-ancestors-static-section"></docs-demo-sources>
    <demo-wait-ancestors-static-section></demo-wait-ancestors-static-section>

Dynamic (child added on button click):

<docs-demo-sources for="demo-wait-ancestors-ready-section"></docs-demo-sources>
    <demo-wait-ancestors-ready-section></demo-wait-ancestors-ready-section>

CSS selector support

Parameters are CSS selectors matched via element.matches() — e.g. "sonic-subscriber", "sonic-subscriber[dataProvider]", ".my-container", or multiple: "sonic-subscriber", "sonic-sdui".

Behavior

Use cases

These decorators are particularly useful for:

Listening to the connected event

The sonic-connected event bubbles, so you can listen to it from anywhere:

import { CONNECTED } from "@supersoniks/concorde/decorators";

someConnectable.addEventListener(CONNECTED, (e) => {
  console.log("Component connected:", e.target);
});

Notes