I would like to define a custom element and attach it in a shadow dom. This element use alpine and bootstrap4 and must be graphically isolated from the rest of the dom. Alpine must be included and used directly inside the webcomponent (not in the light dom).

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous" />
<script defer src="https://unpkg.com/alpinejs@3.9.3/dist/cdn.min.js"></script>

<div class="container" x-data="my_component">
  <div class="row">
    <div class="col-lg-2 col-md-4">
      <div class="form-group">
        <label for="sel1">Sel 1</label>
        <select id="sel1" class="form-control" x-model="sel1">
          <option value="" disabled>Sel 1</option>
          <template x-for="{label, id} in optsSel1" :key="id">
                  <option
                    x-text="label"
                    x-bind:value="id"
                    x-bind:selected="id === sel1"
                  ></option>
                </template>
        </select>
      </div>
    </div>
  </div>
  <div class="row mt-xs-3 mt-sm-3">
    <div class="col-lg-12 text-center">
      <button class="btn btn-warning btn-lg btn-block" @click="notify">
              Submit
            </button>
    </div>
  </div>
</div>

<script>
  const optsSel1 = [{
      id: "AF",
      label: "Afghanistan"
    },
    {
      id: "AL",
      label: "Albania"
    },
    {
      id: "DZ",
      label: "Algeria"
    }
  ];

  document.addEventListener("alpine:init", () => {
    Alpine.data("my_component", () => ({
      optsSel1,
      sel1: "AF",
      notify() {
        const data = new URLSearchParams({
          sel1: this.sel1
        });

        alert(data);
      }
    }));
  });
</script>

I tried to wrap the code above in a template tag and define a custom element.

Graphically is ok, bootstrap seems to work.

JS works too indeed on alpine:init an alert is shown.

But all the logic defined in alpine that interact with the dom seems to not work:

  1. select’s options are empty;
  2. click on submit button has no effect.
<!DOCTYPE html>
<html lang="it">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
</head>

<body>
  <div>
    <button class="btn btn-warning btn-lg btn-block">button outside</button>
    <my-component />
  </div>
  <template id="my-component_tpl">
      <link
        rel="stylesheet"
        href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css"
        integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
        crossorigin="anonymous"
      />
      <script defer src="https://unpkg.com/alpinejs@3.9.3/dist/cdn.min.js"></script>

      <div class="container" x-data="my_component">
        <div class="row">
          <div class="col-lg-2 col-md-4">
            <div class="form-group">
              <label for="sel1">Sel 1</label>
              <select id="sel1" class="form-control" x-model="sel1">
                <option value="" disabled>Sel 1</option>
                <template x-for="{label, id} in optsSel1" :key="id">
                  <option
                    x-text="label"
                    x-bind:value="id"
                    x-bind:selected="id === sel1"
                  ></option>
                </template>
  </select>
  </div>
  </div>
  </div>
  <div class="row mt-xs-3 mt-sm-3">
    <div class="col-lg-12 text-center">
      <button class="btn btn-warning btn-lg btn-block" @click="notify">
              Submit
            </button>
    </div>
  </div>
  </div>

  <script>
    const optsSel1 = [{
        id: "AF",
        label: "Afghanistan"
      },
      {
        id: "AL",
        label: "Albania"
      },
      {
        id: "DZ",
        label: "Algeria"
      }
    ];

    document.addEventListener("alpine:init", () => {
      alert("alpine:init " + JSON.stringify(optsSel1, null, 2));
      Alpine.data("my_component", () => ({
        optsSel1,
        sel1: "AF",
        notify() {
          const data = new URLSearchParams({
            sel1: this.sel1
          });

          alert(data);
        }
      }));
    });
  </script>
  </template>

  <script>
    customElements.define(
      "my-component",
      class extends HTMLElement {
        connectedCallback() {
          const shadow = this.attachShadow({
            mode: "open"
          });

          const tpl = document.getElementById("my-component_tpl");

          shadow.appendChild(tpl.content);
        }
      }
    );
  </script>
</body>

</html>

What’s wrong? Thanks in advance!