Adapt a multi input with JavasScript and Alpine JS

I have a multi input made with alpine js, is not mine, I search for one on Google and like this one. So, the problem is that 3 inputs on my form needs to be multi-options available, but the first input options repeat for all inputs (They should be different for each input).

I know is because that the input was implemented for 1 multi input per form, but I need to adapt it and I don’t know have any idea of what to do. (I’m a Django dev, I don’t have knowledge in alpine js at all and my knowledge of JavaScript is pretty basic).

If a pure soul can help me to adapt it or, at least, guide me how to do it, it would help. Thanks.

Dependencies: Tailwind (lasted stable), Alpine JS (lasted stable)

  <section class="w-full">
    <select x-cloak id="select" style="display:none" class="text-gray-400">
      <option value="Preescolar">Preescolar</option>
      <option value="Educ. Básica">Educ. Básica</option>
      <option value="Educ. Media">Educ. Media</option>
    </select>

    <label class="w-full text-sm">
      <span class="text-gray-700 dark:text-gray-400">Nivel/es</span>
      <div x-data="dropdown()" x-init="loadOptions()" class="h-fit w-full flex flex-col items-center mx-auto">
        <input name="values" type="hidden" x-bind:value="selectedValues()" readonly="readonly">
        <div class="inline-block relative w-full">
          <div class="flex flex-col items-center relative">
            <div x-on:click="open" class="w-full svelte-1l8159u">
              <div class="mt-1 p-2 flex rounded border dark:border-gray-600 dark:bg-gray-700 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:text-gray-400 dark:focus:shadow-outline-gray svelte-1l8159u">
                <div class="flex flex-auto flex-wrap grow gap-1">
                  <template x-for="(option,index) in selected" :key="options[option].value">
                    <div
                      class="flex justify-center gap-1 items-center font-medium pl-1 pr-0.5 rounded text-purple-700 bg-purple-100 border border-purple-300">
                      <div class="text-xs font-normal leading-none max-w-full flex-initial" x-model="options[option]" x-text="options[option].text"></div>
                      <div class="flex flex-auto flex-row-reverse">
                        <div x-on:click="remove(index,option)">
                          <svg xmlns="http://www.w3.org/2000/svg" role="button" viewBox="0 0 20 20" fill="currentColor" class="size-4 fill-current">
                            <path d="M6.28 5.22a.75.75 0 0 0-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 1 0 1.06 1.06L10 11.06l3.72 3.72a.75.75 0 1 0 1.06-1.06L11.06 10l3.72-3.72a.75.75 0 0 0-1.06-1.06L10 8.94 6.28 5.22Z" />
                          </svg>
                        </div>
                      </div>
                    </div>
                  </template>
                  <div x-show="selected.length == 0" class="flex-1">
                    <input placeholder="..."
                      class="bg-transparent p-0 border-none appearance-none outline-none h-full w-full text-gray-400 text-sm"
                      x-bind:value="selectedValues()" readonly="readonly">
                  </div>
                </div>
                <div
                  class="w-fit pl-2 border-l flex items-center border-gray-600 svelte-1l8159u">
                  <button type="button" x-show="isOpen() === true" x-on:click="open"
                    class="cursor-pointer outline-none focus:outline-none">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5 cursor-pointer outline-none focus:outline-none">
                      <path fill-rule="evenodd" d="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
                    </svg>
                  </button>
                  <button type="button" x-show="isOpen() === false" @click="close"
                    class="cursor-pointer outline-none focus:outline-none">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5 cursor-pointer outline-none focus:outline-none">
                      <path fill-rule="evenodd" d="M9.47 6.47a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 1 1-1.06 1.06L10 8.06l-3.72 3.72a.75.75 0 0 1-1.06-1.06l4.25-4.25Z" clip-rule="evenodd" />
                    </svg>  
                  </button>
                </div>
              </div>
            </div>
            <div class="w-full px-4">
              <div x-show.transition.origin.top="isOpen()"
                class="absolute shadow top-100 text-gray-400 bg-gray-700 z-40 w-full left-0 rounded max-h-select overflow-y-auto svelte-5uyqqj"
                x-on:click.away="close">
                <div class="flex flex-col w-full">
                  <template x-for="(option,index) in options" :key="option">
                    <div>
                      <div class="cursor-pointer w-full border-gray-600 rounded-b border-b hover:bg-purple-700"
                        @click="select(index,$event)">
                        <div x-bind:class="option.selected ? 'border-purple-600' : ''"
                          class="flex w-full items-center p-2 pl-2 hover:text-gray-100 relative">
                          <div class="w-full items-center flex">
                            <div class="mx-2 leading-6" x-model="option" x-text="option.text"></div>
                          </div>
                        </div>
                      </div>
                    </div>
                  </template>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </label>
  </section>

  <section class="w-full">
    <select x-cloak id="select" style="display:none" class="text-gray-400">
      {% for course in courses %}
      <option value="1">{{course.grade}}</option>
      {% endfor %}
    </select>

    <label class="w-full text-sm">
      <span class="text-gray-700 dark:text-gray-400">Sección/es</span>
      <div x-data="dropdown()" x-init="loadOptions()" class="h-fit w-full flex flex-col items-center mx-auto">
        <input name="values" type="hidden" x-bind:value="selectedValues()">
        <div class="inline-block relative w-full">
          <div class="flex flex-col items-center relative">
            <div x-on:click="open" class="w-full svelte-1l8159u">
              <div class="mt-1 p-2 flex rounded border dark:border-gray-600 dark:bg-gray-700 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:text-gray-400 dark:focus:shadow-outline-gray svelte-1l8159u">
                <div class="flex flex-auto flex-wrap grow gap-1">
                  <template x-for="(option,index) in selected" :key="options[option].value">
                    <div
                      class="flex justify-center gap-1 items-center font-medium pl-1 pr-0.5 rounded text-purple-700 bg-purple-100 border border-purple-300">
                      <div class="text-xs font-normal leading-none max-w-full flex-initial" x-model="options[option]" x-text="options[option].text"></div>
                      <div class="flex flex-auto flex-row-reverse">
                        <div x-on:click="remove(index,option)">
                          <svg xmlns="http://www.w3.org/2000/svg" role="button" viewBox="0 0 20 20" fill="currentColor" class="size-4 fill-current">
                            <path d="M6.28 5.22a.75.75 0 0 0-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 1 0 1.06 1.06L10 11.06l3.72 3.72a.75.75 0 1 0 1.06-1.06L11.06 10l3.72-3.72a.75.75 0 0 0-1.06-1.06L10 8.94 6.28 5.22Z" />
                          </svg>
                        </div>
                      </div>
                    </div>
                  </template>
                  <div x-show="selected.length == 0" class="flex-1">
                    <input placeholder="..."
                      class="bg-transparent p-0 border-none appearance-none outline-none h-full w-full text-gray-400 text-sm"
                      x-bind:value="selectedValues()">
                  </div>
                </div>
                <div
                  class="w-fit pl-2 border-l flex items-center border-gray-600 svelte-1l8159u">
                  <button type="button" x-show="isOpen() === true" x-on:click="open"
                    class="cursor-pointer outline-none focus:outline-none">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5 cursor-pointer outline-none focus:outline-none">
                      <path fill-rule="evenodd" d="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
                    </svg>
                  </button>
                  <button type="button" x-show="isOpen() === false" @click="close"
                    class="cursor-pointer outline-none focus:outline-none">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5 cursor-pointer outline-none focus:outline-none">
                      <path fill-rule="evenodd" d="M9.47 6.47a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 1 1-1.06 1.06L10 8.06l-3.72 3.72a.75.75 0 0 1-1.06-1.06l4.25-4.25Z" clip-rule="evenodd" />
                    </svg>  
                  </button>
                </div>
              </div>
            </div>
            <div class="w-full px-4">
              <div x-show.transition.origin.top="isOpen()"
                class="absolute shadow top-100 text-gray-400 bg-gray-700 z-40 w-full left-0 rounded max-h-select overflow-y-auto svelte-5uyqqj"
                x-on:click.away="close">
                <div class="flex flex-col w-full">
                  <template x-for="(option,index) in options" :key="option">
                    <div>
                      <div class="cursor-pointer w-full border-gray-600 rounded-b border-b hover:bg-purple-700"
                        @click="select(index,$event)">
                        <div x-bind:class="option.selected ? 'border-purple-600' : ''"
                          class="flex w-full items-center p-2 pl-2 hover:text-gray-100 relative">
                          <div class="w-full items-center flex">
                            <div class="mx-2 leading-6" x-model="option" x-text="option.text"></div>
                          </div>
                        </div>
                      </div>
                    </div>
                  </template>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </label>
  </section>

  <section class="w-full">
    <select x-cloak id="select" style="display:none" class="text-gray-400">
      <option value="1">Option 2</option>
      <option value="2">Option 3</option>
      <option value="3">Option 4</option>
      <option value="4">Option 5</option>
    </select>

    <label class="w-full text-sm">
      <span class="text-gray-700 dark:text-gray-400">Materia/s</span>
      <div x-data="dropdown()" x-init="loadOptions()" class="h-fit w-full flex flex-col items-center mx-auto">
        <input name="values" type="hidden" x-bind:value="selectedValues()">
        <div class="inline-block relative w-full">
          <div class="flex flex-col items-center relative">
            <div x-on:click="open" class="w-full svelte-1l8159u">
              <div class="mt-1 p-2 flex rounded border dark:border-gray-600 dark:bg-gray-700 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:text-gray-400 dark:focus:shadow-outline-gray svelte-1l8159u">
                <div class="flex flex-auto flex-wrap grow gap-1">
                  <template x-for="(option,index) in selected" :key="options[option].value">
                    <div
                      class="flex justify-center gap-1 items-center font-medium pl-1 pr-0.5 rounded text-purple-700 bg-purple-100 border border-purple-300">
                      <div class="text-xs font-normal leading-none max-w-full flex-initial" x-model="options[option]" x-text="options[option].text"></div>
                      <div class="flex flex-auto flex-row-reverse">
                        <div x-on:click="remove(index,option)">
                          <svg xmlns="http://www.w3.org/2000/svg" role="button" viewBox="0 0 20 20" fill="currentColor" class="size-4 fill-current">
                            <path d="M6.28 5.22a.75.75 0 0 0-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 1 0 1.06 1.06L10 11.06l3.72 3.72a.75.75 0 1 0 1.06-1.06L11.06 10l3.72-3.72a.75.75 0 0 0-1.06-1.06L10 8.94 6.28 5.22Z" />
                          </svg>
                        </div>
                      </div>
                    </div>
                  </template>
                  <div x-show="selected.length == 0" class="flex-1">
                    <input placeholder="..."
                      class="bg-transparent p-0 border-none appearance-none outline-none h-full w-full text-gray-400 text-sm"
                      x-bind:value="selectedValues()">
                  </div>
                </div>
                <div
                  class="w-fit pl-2 border-l flex items-center border-gray-600 svelte-1l8159u">
                  <button type="button" x-show="isOpen() === true" x-on:click="open"
                    class="cursor-pointer outline-none focus:outline-none">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5 cursor-pointer outline-none focus:outline-none">
                      <path fill-rule="evenodd" d="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
                    </svg>
                  </button>
                  <button type="button" x-show="isOpen() === false" @click="close"
                    class="cursor-pointer outline-none focus:outline-none">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5 cursor-pointer outline-none focus:outline-none">
                      <path fill-rule="evenodd" d="M9.47 6.47a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 1 1-1.06 1.06L10 8.06l-3.72 3.72a.75.75 0 0 1-1.06-1.06l4.25-4.25Z" clip-rule="evenodd" />
                    </svg>  
                  </button>
                </div>
              </div>
            </div>
            <div class="w-full px-4">
              <div x-show.transition.origin.top="isOpen()"
                class="absolute shadow top-100 text-gray-400 bg-gray-700 z-40 w-full left-0 rounded max-h-select overflow-y-auto svelte-5uyqqj"
                x-on:click.away="close">
                <div class="flex flex-col w-full">
                  <template x-for="(option,index) in options" :key="option">
                    <div>
                      <div class="cursor-pointer w-full border-gray-600 rounded-b border-b hover:bg-purple-700"
                        @click="select(index,$event)">
                        <div x-bind:class="option.selected ? 'border-purple-600' : ''"
                          class="flex w-full items-center p-2 pl-2 hover:text-gray-100 relative">
                          <div class="w-full items-center flex">
                            <div class="mx-2 leading-6" x-model="option" x-text="option.text"></div>
                          </div>
                        </div>
                      </div>
                    </div>
                  </template>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </label>
  </section>

<script>
function dropdown() {
  return {
    options: [],
    selected: [],
    show: false,
    open() { this.show = true },
    close() { this.show = false },
    isOpen() { return this.show === true },
    select(index, event) {

      if (!this.options[index].selected) {

        this.options[index].selected = true;
        this.options[index].element = event.target;
        this.selected.push(index);

      } else {
        this.selected.splice(this.selected.lastIndexOf(index), 1);
        this.options[index].selected = false
      }
    },
    remove(index, option) {
      this.options[option].selected = false;
      this.selected.splice(index, 1);
    },
    loadOptions() {
      const options = document.getElementById('select').options;
      for (let i = 0; i < options.length; i++) {
        this.options.push({
          value: options[i].value,
          text: options[i].innerText,
          selected: options[i].getAttribute('selected') != null ? options[i].getAttribute('selected') : false
        });
      }
    },
    selectedValues() {
      return this.selected.map((option) => {
        return this.options[option].value;
      })
    }
  }
}
</script>