Getter and setter ignored in a custom element

I came accross an odd problem using WebComponents and composing them. I created a minimal HTML page to reproduce the problem.

I’m basically trying to build the following structure :

  • custom list
  • containing custom items
  • each item containing a custom input to show the item name

My custom input is a wrapper to add label to a basic input and I use get and set on my custom input so that its value mirror the basic input value.

It works perfectly in isolation : getting and setting the value of my custom input gets and sets the value of the basic input inside it.
It also works fine inside my custom item : getting and setting its item correctly mirrors the item name on the custom input.

But when I manage items through my custom list, it breaks. The getter and setter of my custom input seem to have disappeared and fallback to a normal property with no accessors functions.

Here’s the minimal code to reproduce the problem :

    const customInputTemplate = document.createElement("template");
    customInputTemplate.innerHTML = `
    <label id="label" for="input"></label>
    <input id="input" type="text" />
    `;

    window.customElements.define("my-custom-input", class MyCustomInput extends HTMLElement {
      static get observedAttributes() {
        return ["label"]
      }

      constructor() {
        super();
        this.attachShadow({ mode: "open"});
        this.shadowRoot.appendChild(customInputTemplate.content.cloneNode(true));

        this.labelElemenet =  this.shadowRoot.getElementById("label");
        this.inputElement = this.shadowRoot.getElementById("input");
      }

      get value() { // This seems to be ignored or unset in certain cases
        return this.inputElement.value;
      }

      set value(newValue) { // This also has the problem
        this.inputElement.value = newValue;
      }

      attributeChangedCallback(name, oldValue, newValue) {
        if (name === "label") {
          this.labelElemenet.innerText = newValue;
        }
      }
    });

    const customItemTemplate = document.createElement("template");
    customItemTemplate.innerHTML = `
      <li>
        <my-custom-input id="custom-input" label="Item :"></my-custom-input>
      </li>
    `;

    window.customElements.define("my-custom-item", class MyCustomItem extends HTMLElement {
      #item;

      constructor() {
        super();
        this.attachShadow({ mode: "open"});
        this.shadowRoot.appendChild(customItemTemplate.content.cloneNode(true));

        this.customInputElement =  this.shadowRoot.getElementById("custom-input");
      }

      get item() {
        return this.#item;
      }

      set item(newItem) {
        this.#item = newItem;
        this.#render();
      }

      #render() {
        if (this.customInputElement.value !== this.#item.name) {
          this.customInputElement.value = this.#item.name
        }
      }
    });

    const customListTemplate = document.createElement("template");
    customListTemplate.innerHTML = `
      <ul>
        <slot></slot>
      </ul>
    `;

    window.customElements.define("my-custom-list", class MyCustomList extends HTMLElement {
      #items;

      constructor() {
        super();
        this.attachShadow({ mode: "open"});
        this.shadowRoot.appendChild(customListTemplate.content.cloneNode(true));
      }

      get items() {
        return this.#items;
      }

      set items(newItems) {
        this.#items = newItems;
        this.#render();
      }

      #render() {
        this.replaceChildren(...this.#items.map(item => {
          const itemElement = document.createElement("my-custom-item");
          itemElement.item = item; // This is where things get broken
          return itemElement;
        }));
      }
    });

    const customInputElement = document.getElementById("my-custom-input");
    customInputElement.value = "Some value for my custom input";

    const customItemElement = document.getElementById("my-custom-item");
    customItemElement.item = { id: "Z", name: "Some name for my custom item"};

    const listElement = document.getElementById("my-list");

    listElement.items = [
      { id: "A", name: "Item A" },
      { id: "B", name: "Item B" },
      { id: "C", name: "Item C" },
    ];

    // All inputs are empty instead of showing the item names

    const firstItem = listElement.querySelector("my-custom-item");
    const customInputOfFirstItem = firstItem.shadowRoot.querySelector("my-custom-input");

    console.log("customInputOfFirstItem.value = ", customInputOfFirstItem.value); // Correctly logs "Item A"

    // Trying to force value
    customInputOfFirstItem.value = "Updated item A";
    console.log("After forcing value, customInputOfFirstItem.value = ", customInputOfFirstItem.value); // Correctly logs "Updated item A"

    // But ...
    const originalInput = customInputOfFirstItem.shadowRoot.getElementById("input");
    console.log("Original input value = ", originalInput.value); // Logs empty value
    // Forcing it
    originalInput.value = "Forced inside value for item A";
    console.log("After forcing inside value, customInputOfFirstItem.value = ", customInputOfFirstItem.value); // Still logs "Updated item A"

    // It's acting as if getter (line 37) and setter (line 41) where ignored or somewhat unset in the process
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Web Component</title>
</head>

<body>
  <h3>Custom input, works fine</h3>
  <my-custom-input id="my-custom-input" label="Custom input"></my-custom-input>

  <h3>Custom item, also works fine</h3>
  <my-custom-item id="my-custom-item"></my-custom-item>

  <h3>Inside custom list, does not work</h3>
  <my-custom-list id="my-list"></my-custom-list>
</body>

</html>