HTML slots: fix missing assigned content and track changes

A named HTML slot displays matching direct children of its shadow host. If a button with slot="actions" disappears after you wrap it in a div, move the slot attribute to the direct child you want assigned. To detect an action being added or removed, listen for slotchange and inspect assignedElements().

In this original example, a delivery notice starts with no action. The page later adds a “View delivery” link. The component needs to know whether that action region is occupied; it does not need to watch every letter in the link label.

Give the changing region a named slot

Save this complete fragment in a test HTML page:

<delivery-notice id="notice"></delivery-notice>
<script>
class DeliveryNotice extends HTMLElement {
  constructor() {
    super();
    const root = this.attachShadow({ mode: 'open' });
    root.innerHTML = `
      <p>Delivery information</p>
      <slot name="actions">No action available.</slot>
      <p id="state"></p>
    `;
    const slot = root.querySelector('slot');
    const report = () => {
      root.querySelector('#state').textContent =
        slot.assignedElements().length + ' assigned action(s)';
    };
    slot.addEventListener('slotchange', report);
    report();
  }
}
customElements.define('delivery-notice', DeliveryNotice);
const notice = document.querySelector('#notice');
const link = document.createElement('a');
link.slot = 'actions';
link.href = '#delivery';
link.textContent = 'View delivery';
notice.append(link);
</script>
<h2 id="delivery">Delivery details</h2>

After assignment has settled, the link is visible and the count is 1. The literal fallback “No action available.” is hidden. The link still belongs to the host's ordinary DOM; slotting changes where it appears.

The slot element reference, checked October 24, 2026, describes the distribution rules. The template and static-slot guide covers building a reusable template first.

Find the actual direct child

This arrangement does not assign the link to the named slot:

<delivery-notice>
  <div><a slot="actions" href="#delivery">View delivery</a></div>
</delivery-notice>

The host's direct child is the div. Put slot="actions" on that div if the entire wrapper should occupy the action region. With the earlier component, a wrapper carrying no slot name has nowhere visible to go because there is no default slot.

Inspect notice.children and the slot's assignedElements() separately. If the wrapper appears only in the first collection, check its slot name before changing CSS. A spelling mismatch produces the same empty assignment.

Treat assignment and text updates separately

Run these operations one at a time after the initial assignment:

Operation Assigned element count afterward Assignment event expected
Change link.textContent to Track delivery 1 No
Remove the link from the host 0 Yes
Append the link to the host again 1 Yes

Changing the label changes content inside an assigned node. It does not change which node is assigned. MDN's slotchange documentation makes that distinction. Multiple assignment edits can be reported together, so read the final assignment in the handler instead of treating events as an edit counter.

The displayed count deliberately counts elements. Use assignedNodes() when text nodes also matter, and define how whitespace should count for your task. A whitespace-only text node can affect fallback in a default slot, so “no visible text” is not always the same as “no assigned nodes.”

Check the caller before rewriting the component

Remove and reinsert the action in the actual page, then inspect the fallback and the count after each operation. Change the label separately and confirm the visible link updates even though assignment stays the same. The web component lifecycle guide helps when the tag never upgrades at all. Once the host supplies the intended direct child, leave the component's structural template alone unless the layout itself needs to change.

Keep reading