title: Removing nodes from tree view built with Lit
body: <p>I'm trying to build an interactive tree-like component using Lit, and I'm running into some issues when trying to remove tree nodes. Here's the implementation of the component:</p>
  <pre class="lang-js prettyprint-override"><code>import { html, LitElement } from 'https://cdn.jsdelivr.net/gh/lit/dist@2/all/lit-all.min.js';
  
  let counter = 0;
  
  export class TreeNode extends LitElement {
      static properties = {
          label: { type: String },
          children: { state: true }
      };
  
      constructor() {
          super();
          this.children = [];
      }
  
      render() {
          return html`
              &lt;div&gt;
                  ${this.label}
                  &lt;button @click=${this.onAddButtonClick}&gt;add child&lt;/button&gt;
                  &lt;button @click=${this.onRemoveButtonClick}&gt;remove&lt;/button&gt;
              &lt;/div&gt;
              &lt;ul&gt;
                  ${this.children.map(child =&gt; html`
                      &lt;li&gt;
                          &lt;tree-node label=${child.label} @remove=${(ev) =&gt; { ev.stopPropagation(); this.removeChild(child.id); }}&gt;&lt;/tree-node&gt;
                      &lt;/li&gt;
                  `)}
              &lt;/ul&gt;
          `;
      }
  
      onAddButtonClick() {
          const id = counter++;
          this.children = [...this.children, { id, label: `Node #${id}` }];
      }
  
      onRemoveButtonClick() {
          this.dispatchEvent(new Event('remove', { bubbles: true, composed: true }));
      }
  
      removeChild(id) {
          this.children = this.children.filter(child =&gt; child.id !== id);
      }
  }
  
  customElements.define('tree-node', TreeNode);
  
  export class TreeView extends LitElement {
      render() {
          return html`&lt;tree-node label=&quot;root&quot;&gt;&lt;/tree-node&gt;`;
      }
  }
  
  customElements.define('tree-view', TreeView);
  </code></pre>
  <p>And a working example is here: <a href="https://codepen.io/petrbroz/pen/wvyzzPp" rel="nofollow noreferrer">https://codepen.io/petrbroz/pen/wvyzzPp</a></p>
  <p>Now, let's say I have the following tree structure:</p>
  <pre><code>- Node A
    - Node B
      - Node C
      - Node D
      - Node E
    - Node F
  </code></pre>
  <p>Now, if I try to remove <code>Node B</code>, its children are not removed, but instead they become children of <code>Node F</code>. Why is that? Am I doing something wrong in the implementation? I've been able to work around this by manually passing the children to nested nodes as shown below, but I'd like to understand why the original implementation isn't working. Thanks!</p>
  <pre class="lang-js prettyprint-override"><code>import { html, LitElement } from 'https://cdn.jsdelivr.net/gh/lit/dist@2/all/lit-all.min.js';
  
  let counter = 0;
  
  export class TreeNode extends LitElement {
      static properties = {
          label: { type: String },
          children: { type: Array }
      };
  
      constructor() {
          super();
          this.children = [];
      }
  
      render() {
          return html`
              &lt;div&gt;
                  ${this.label}
                  &lt;button @click=${this.onAddButtonClick}&gt;add child&lt;/button&gt;
                  &lt;button @click=${this.onRemoveButtonClick}&gt;remove&lt;/button&gt;
              &lt;/div&gt;
              &lt;ul&gt;
                  ${this.children.map(child =&gt; html`
                      &lt;li&gt;
                          &lt;tree-node label=${child.label} .children=${child.children} @remove=${(ev) =&gt; { ev.stopPropagation(); this.removeChild(child.id); }}&gt;&lt;/tree-node&gt;
                      &lt;/li&gt;
                  `)}
              &lt;/ul&gt;
          `;
      }
  
      onAddButtonClick() {
          const id = counter++;
          this.children = [...this.children, { id, label: `Node #${id}`, children: [] }];
      }
  
      onRemoveButtonClick() {
          this.dispatchEvent(new Event('remove', { bubbles: true, composed: true }));
      }
  
      removeChild(id) {
          this.children = this.children.filter(child =&gt; child.id !== id);
      }
  }
  
  customElements.define('tree-node', TreeNode);
  
  export class TreeView extends LitElement {
      render() {
          return html`&lt;tree-node label=&quot;root&quot;&gt;&lt;/tree-node&gt;`;
      }
  }
  
  customElements.define('tree-view', TreeView);
  </code></pre>