Keep Tom Select Dropdown on screen

https://github.com/orchidjs/tom-select/discussions/393

by Mdot

HTML

<script src="https://cdn.jsdelivr.net/gh/orchidjs/[email protected]/dist/js/tom-select.complete.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orchidjs/[email protected]/dist/css/tom-select.bootstrap5.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<div class="p-4 container"> <select id="select-tags" multiple placeholder="Best movies and TV shows">
    <optgroup label="TV Shows">
      <option value="Blue Bloods" data-date="2010-2021">Blue Bloods (2010-2021)</option>
      <option value="Magnum P.I." data-date="1980-1988" selected>Magnum P.I. (1980-1988)</option>
    </optgroup>
    <optgroup label="Movies">
      <option value="An Innocent Man" data-date="1989">An Innocent Man (1989)</option>
      <option value="In & Out" data-date="1997">In & Out (1997)</option>
      <option value="Lassiter" data-date="1984">Lassiter (1984)</option>
      <option value="Mr. Baseball" data-date="1992">Mr. Baseball (1992)</option>
      <option value="Quigley Down Under" data-date="1990">Quigley Down Under (1990)</option>
      <option value="Three Men and a Baby" data-date="1987">Three Men and a Baby (1987)</option>
    </optgroup>
  </select>
</div>

CSS

html {
  height: 200vh;
}

.container {
  margin-top: 80vh;
}

.ts-control.dropdown-top .ts-dropdown,
.ts-wrapper.dropdown-top .ts-dropdown {
  bottom: 100%;
  top: auto;
}

JavaScript

new TomSelect("#select-tags", {
  onInitialize: function() {
    this.dropdownWatch = null;
    this.dropdownWatchCb = () => {
      if (this.isOpen) {
        const controlRect = this.control.getBoundingClientRect();
        const dropdownRect = this.dropdown.getBoundingClientRect();
        const spaceAbove = controlRect.top;
        const spaceBelow = window.innerHeight - controlRect.bottom;

        if (
          spaceBelow < dropdownRect.height && spaceAbove > spaceBelow
        ) {
          this.wrapper.classList.add('dropdown-top');
        } else {
          this.wrapper.classList.remove('dropdown-top');
        }
      }
    }
  },
  onDropdownOpen: function() {
    this.dropdownWatchCb();
    this.dropdownWatch = setInterval(this.dropdownWatchCb, 250);
  },
  onDropdownClose: function() {
    clearInterval(this.dropdownWatch)
  },
});