Menu

Advanced select

Tom Select turns a `<select>` into a searchable, keyboard-friendly dropdown, for long option lists, multi-value fields and options with an avatar or a flag.

Overview

Tom Select attaches to a normal <select class="form-select"> and replaces it with a searchable dropdown. The original <select> stays in the DOM and keeps its value, so it still works in a plain HTML form.

<select class="form-select" id="select-overview" data-placeholder="Pick a fruit">
  <option value="apple">Apple</option>
  <option value="banana">Banana</option>
  <option value="cherry">Cherry</option>
  <option value="date">Date</option>
  <option value="elderberry">Elderberry</option>
</select>

Installation

Install Tom Select with npm:

npm install tom-select
yarn add tom-select
pnpm install tom-select
bun install tom-select

Or include it from a CDN. You need both the script and its stylesheet:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/[email protected]/dist/libs/tom-select/dist/css/tom-select.bootstrap5.min.css" />
<script src="https://cdn.jsdelivr.net/npm/@tabler/[email protected]/dist/libs/tom-select/dist/js/tom-select.base.min.js"></script>

Compiling the Sass sources

Use the compiled tom-select.bootstrap5.css. Tom Select's Sass sources read Bootstrap variables such as $border-color and pass them to color.adjust(), and in Tabler those variables hold CSS custom properties like var(--gray-200), so Sass stops with $color: var(--gray-200) is not a color. If you still want to compile it, set the variables Tom Select adjusts to plain colors first:

// `as *` keeps Tabler's variables visible to the @import below
@use '@tabler/core/scss/tabler' as *;

$select-color-text: #182433;
$select-color-item-border: #e6e7e9;
@import 'tom-select/dist/scss/tom-select.bootstrap5';

Usage

Basic select

Add class="form-select" to a <select>, give it an id, then attach Tom Select to that id.

<select class="form-select" id="select-basic">
  <option value="apple">Apple</option>
  <option value="banana">Banana</option>
  <option value="cherry">Cherry</option>
</select>
new TomSelect('#select-basic', {
  copyClassesToDropdown: false,
});

Placeholder

Native <select> elements don't support the placeholder attribute, so add data-placeholder instead. Tom Select reads it and shows it as the empty-state text.

<select class="form-select" id="select-placeholder" data-placeholder="Pick a fruit">
  <option value="apple">Apple</option>
  <option value="banana">Banana</option>
  <option value="cherry">Cherry</option>
</select>

Multiple values

Add the multiple attribute to let users pick more than one option. Tom Select shows each pick as a removable tag.

<select class="form-select" id="select-multiple" multiple="true" data-placeholder="Pick fruits">
  <option value="apple">Apple</option>
  <option value="banana">Banana</option>
  <option value="cherry">Cherry</option>
  <option value="date">Date</option>
  <option value="elderberry">Elderberry</option>
</select>
new TomSelect('#select-multiple', {
  copyClassesToDropdown: false,
});

Optgroups

Group related options with <optgroup>. Tom Select shows the group label in the dropdown and keeps it searchable.

<select class="form-select" id="select-optgroup" data-placeholder="Pick a fruit">
  <optgroup label="Citrus">
    <option value="orange">Orange</option>
    <option value="lemon">Lemon</option>
    <option value="lime">Lime</option>
  </optgroup>
  <optgroup label="Berries">
    <option value="strawberry">Strawberry</option>
    <option value="blueberry">Blueberry</option>
    <option value="raspberry">Raspberry</option>
  </optgroup>
</select>

Validation states

Add .is-valid or .is-invalid to the <select> to show a validation state. Tom Select carries the class over to its own wrapper, so the field still shows the usual green or red styling.

<div class="mb-3">
  <label class="form-label">Valid select</label>
  <select class="form-select is-valid" id="select-valid" data-placeholder="Pick a fruit">
    <option value="apple" selected>Apple</option>
    <option value="banana">Banana</option>
  </select>
</div>
<div>
  <label class="form-label">Invalid select</label>
  <select class="form-select is-invalid" id="select-invalid" data-placeholder="Pick a fruit">
    <option value="apple">Apple</option>
    <option value="banana">Banana</option>
  </select>
</div>

With an icon

Put the <select> in an .input-icon after an .input-icon-addon, as for an input. The icon shows inside the Tom Select field.

<div class="input-icon">
  <span class="input-icon-addon">
    <!-- Download SVG icon from http://tabler.io/icons/icon/user -->
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false" class="icon">
      <path d="M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0" />
      <path d="M6 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2" />
    </svg>
  </span>
  <select class="form-select" id="select-icon" data-placeholder="Assign to…">
    <option value>Assign to…</option>
    <option value="1">Jane Doe</option>
    <option value="2">Mark Smith</option>
    <option value="3">Amy Kim</option>
  </select>
</div>

Rich options

An option can carry extra markup - an avatar, a flag, a badge - through a data-custom-properties attribute. Read it in a custom render.option / render.item function and show it next to the option text.

<select class="form-select" id="select-avatar" data-placeholder="Assign to…">
  <option value="1" data-custom-properties="<span class=&quot;avatar avatar-xs&quot;>JD</span>">Jane Doe</option>
  <option value="2" data-custom-properties="<span class=&quot;avatar avatar-xs&quot;>MS</span>">Mark Smith</option>
  <option value="3" data-custom-properties="<span class=&quot;avatar avatar-xs&quot;>AK</span>">Amy Kim</option>
</select>
<select class="form-select" id="select-flag" data-placeholder="Pick a country">
  <option value="us" data-custom-properties="<span class=&quot;flag flag-xs flag-country-us&quot;></span>">United States</option>
  <option value="gb" data-custom-properties="<span class=&quot;flag flag-xs flag-country-gb&quot;></span>">United Kingdom</option>
  <option value="de" data-custom-properties="<span class=&quot;flag flag-xs flag-country-de&quot;></span>">Germany</option>
  <option value="fr" data-custom-properties="<span class=&quot;flag flag-xs flag-country-fr&quot;></span>">France</option>
</select>
function renderOption(data, escape) {
  if (data.customProperties) {
    return `<div class="dropdown-item"><span class="dropdown-item-indicator">${data.customProperties}</span>${escape(data.text)}</div>`;
  }
  return `<div>${escape(data.text)}</div>`;
}

new TomSelect('#select-avatar', {
  copyClassesToDropdown: false,
  dropdownParent: 'body',
  render: {
    item: renderOption,
    option: renderOption,
  },
});

Tom Select turns a data-custom-properties attribute into data.customProperties on the option object, so render.option and render.item can read it. escape() keeps user-supplied text safe when it is inserted as HTML.

Common options

These are the options you will need most often. Tom Select has more, and they are listed in its documentation.

Option What it does
copyClassesToDropdown Copies the <select> classes onto the dropdown. Tabler keeps this false and styles the dropdown itself.
dropdownParent Where the dropdown is appended in the DOM, for example 'body' so it is not clipped by a card or modal.
maxItems Maximum number of selected items on a multi-value select.
create true lets users type a value that is not in the option list.
plugins List of Tom Select plugins to enable, for example remove_button.
render.option / render.item Custom render functions for a dropdown option and a selected item.

Accessibility

  • Always add a <label> linked to the <select> with for and id. Tom Select's generated markup does not replace the need for a label.
  • The dropdown can be operated with the keyboard: type to search, arrow keys to move between options, Enter to pick one, and Backspace to remove the last tag on a multi-value select.
  • When using render.option, keep enough text content in the rendered HTML - an avatar or flag alone does not tell a screen reader user which option it is.
  • Escape user-supplied text in custom render functions with the escape argument, so option text can never break out of the generated HTML.