• Combobox WIP

    A searchable dropdown built from a text input and the native Popover API. CSS handles all visual presentation; a small inline script filters the list and wires up selection.

    Each anchor-name must be unique per combobox on the page. Set it via an inline style and reference the same value as position-anchor on the popover.

    Default

  • <div class="combobox">
      <input
        type="search"
        placeholder="Search fruits..."
        style="anchor-name: --my-combobox"
        onfocus="
          setTimeout(
            () =>
              !this.nextElementSibling.matches(':popover-open') &&
              this.nextElementSibling.showPopover(),
          )
        "
        oninput="
          this.nextElementSibling
            .querySelectorAll('li')
            .forEach(
              (li) =>
                (li.hidden = !li.textContent
                  .toLowerCase()
                  .includes(this.value.toLowerCase())),
            )
        "
      />
      <div
        popover
        style="position-anchor: --my-combobox"
        onpointerdown="const b=event.target.closest('button');if(b){event.preventDefault();this.previousElementSibling.value=b.textContent.trim();setTimeout(()=>this.hidePopover())}"
      >
        <menu>
          <li><button class="ghost">Apple</button></li>
          <li><button class="ghost">Banana</button></li>
          <li><button class="ghost">Cherry</button></li>
          <li><button class="ghost">Mango</button></li>
          <li><button class="ghost">Pineapple</button></li>
        </menu>
      </div>
    </div>

    In a field

    Wrap with a <label> to attach a visible label.

    <label>
      Favourite fruit
      <div class="combobox">
        <input
          type="search"
          placeholder="Search..."
          style="anchor-name: --my-combobox"
          onfocus="
            setTimeout(
              () =>
                !this.nextElementSibling.matches(':popover-open') &&
                this.nextElementSibling.showPopover(),
            )
          "
          oninput="
            this.nextElementSibling
              .querySelectorAll('li')
              .forEach(
                (li) =>
                  (li.hidden = !li.textContent
                    .toLowerCase()
                    .includes(this.value.toLowerCase())),
              )
          "
        />
        <div
          popover
          style="position-anchor: --my-combobox"
          onpointerdown="const b=event.target.closest('button');if(b){event.preventDefault();this.previousElementSibling.value=b.textContent.trim();setTimeout(()=>this.hidePopover())}"
        >
          <menu>
            <li><button class="ghost">Apple</button></li>
            <li><button class="ghost">Banana</button></li>
            <li><button class="ghost">Cherry</button></li>
          </menu>
        </div>
      </div>
    </label>

    Search 5021 icons

    Type a name to find icons from the Tabler icon set.