Framework
orchidjs/tom-select avatar
orchidjs/tom-select

Tom Select: a framework agnostic select control forked from selectize.js

Tom Select is a lightweight (~16kb gzipped) hybrid of a textbox and select box. Forked from selectize.js to provide a framework agnostic autocomplete widget with native-feeling keyboard navigation. Useful for tagging, contact lists, etc.

2,232 stars175 forksJavaScriptApache-2.0

At a glance

What is it?
A small autocomplete and tagging widget that dropped the jQuery dependency its parent library carried, shipping ESM, CJS and prebuilt bundles plus a plugin API.
Who is it for?
Tom Select is the right pick when you want selectize's behaviour, jQuery's absence, and a build that hands you ESM, CommonJS and prebuilt files without asking you to configure anything. The bundle variants are the practical detail: take `complete` for the batteries included version with plugins bundled, `base` when you want to add only the plugins you use, and the theme files compiled or as SCSS.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 7, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the fork actually changed

The origin is stated plainly in the README: Tom Select was forked from selectize.js with the goal of modernizing the code base, decoupling from jQuery, and expanding functionality. Those three goals are the design brief. Decoupling from jQuery is the one that matters most in practice, because it moves the library out of the 2010s convention where a UI widget could assume jQuery was already on the page, and it makes the widget usable from a framework component without adapters. Modernizing covers the build and module story, and expanding functionality is where the plugin API comes in.

The positioning is a lightweight control at roughly 16kb gzipped, and that number is doing real work in the pitch. It is small enough to load directly from a CDN on a page that has no build step at all, and small enough to include in an application that already carries a framework. The topics on the repository reflect the intended comparison set, listing select, select-multiple, select2, choices and dropdown alongside vanilla-js and typescript, so the project is unapologetically in the same category as those libraries and wants to be chosen against them.

What it is used for is stated as tagging, contact lists and country selectors. That is the honest description of what a select-and-autocomplete control is actually for: taking a value from a set that is too large for a plain dropdown but not large enough to justify a full search interface.

Three lines of HTML and a constructor

The usage example is as small as this kind of library gets, and it is worth noticing that the input element is an empty `<input>` with an id, not a `<select>`:

html
<input id="tom-select-it" />
<link rel="stylesheet" href="/css/tom-select.default.css">
<script src="/js/tom-select.complete.js"></script>
<script>
var config = {};
new TomSelect('#tom-select-it',config);
</script>

The pattern is: load the stylesheet, load the script, pass a selector and a config object to the constructor. The config object is where everything lives, and the README links out rather than duplicating it, pointing to the documentation site for the available settings. That is a reasonable choice for a library with this many options, but it does mean the README alone is not enough to configure anything non-trivial.

Since it is framework agnostic, the constructor call is also the integration point for React, Vue or anything else: create the control in a lifecycle hook and tear it down when the component unmounts, because the control manages its own DOM inside your input. There is no adapter package in this repository, so if you are using a framework you will be writing that wrapper yourself.

Three bundles and what falls inside each

The `package.json` and the README's Files section together describe a deliberate set of distribution variants. `main` points at `dist/cjs/tom-select.complete.js` for CommonJS, `module` at `dist/esm/tom-select.complete.js` for bundlers, `browser` at a UMD build, and `style` at the compiled default CSS. There is also an `exports` map with separate entry points beyond the default, which is the detail that tells you the library is built around variants rather than one bundle:

json
  "exports": {
    ".": {
      "import": "./dist/esm/tom-select.complete.js",
      "require": "./dist/cjs/tom-select.complete.js"
    },
    "./base": {
      "import": "./dist/esm/tom-select.js",
      "require": "./dist/cjs/tom-select.js"
    },

The README states the difference between the two main variants directly: `tom-select.complete.js` includes dependencies and plugins, while `tom-select.base.js` does not include any plugins. There is a third flavour named in the docs, a `popular` entry in the exports map alongside `base` and `utils`, which suggests a middle ground between nothing and everything. If you are shipping a bundle size budget, the `base` entry plus the specific plugins you use is the version to reach for.

For themes, the README lists compiled CSS in `dist/css` and uncompiled SCSS sources in `dist/scss`, and the file name `tom-select.default.css` implies at least one alternative theme. For installation, three routes are offered: jsDelivr for the fastest CDN include, npm with `npm i tom-select`, or cloning the repository and running `npm run build`. The manifests carry a little oddity worth noting for anyone automating a build: there is a `composer.json` in a JavaScript library, presumably to publish to Packagist, and an `overrides` block pinning `fflate` to a specific version.

Features that come from the plugin layer

Several of the more interesting behaviours are plugins rather than core, which is worth knowing before you assume a feature is built in. The caret position plugin adds the ability to move between already selected items with the left and right arrow keys, which matters when order is semantically meaningful and a plain tag input does not let you reposition items easily. The plugin system itself is described as extensible and built on microplugin.

Search is a core feature and it is the one most worth evaluating on its own merits. Options are scored and sorted on the fly using sifter, and the README notes you can search an item's title and its description at once. That ranking is what separates a usable autocomplete from a filtered list, since it handles substring matches in the middle of a word, matches against multiple fields, and orders by relevance rather than alphabetically.

The remaining core items are about handling real data. Multi-select for deletion works by holding command on Mac or ctrl on Windows to select several items and remove them together. Diacritics are supported, which the README flags as important for international environments, so a search for a name typed without accents still matches. Item creation lets users add entries that were not in the original list, and asynchronous saving is supported with the control locking until the callback fires, which is the correct way to avoid a race between saving a new tag and selecting it. Remote data loading covers the case where you have thousands of options and want them supplied by the server as the user types.

Accessibility, touch support and a clean API are claimed in the feature list without elaboration, and the documentation site is where you would verify them. The release history shows active work on the plugin layer specifically: v2.6.2 in July 2026 fixes preloaded options bleeding into search results in virtual scroll, allows a null maxOptions in virtual scroll, and lets you edit the HTML for the remove button plugin. v2.6.1 in May 2026 fixes virtual scroll losing preloaded options after a search and avoids stealing focus if the control was moved before its onFocus fired. That is the kind of bug that only shows up once real users type into the control, so it is a reasonable signal of adoption. The repository is Apache-2.0, with the licence text in the README attributing copyright to contributors from 2013 onward, matching the selectize.js lineage.

Editorial conclusion

Tom Select is the right pick when you want selectize's behaviour, jQuery's absence, and a build that hands you ESM, CommonJS and prebuilt files without asking you to configure anything. The bundle variants are the practical detail: take `complete` for the batteries included version with plugins bundled, `base` when you want to add only the plugins you use, and the theme files compiled or as SCSS. Search ranking through sifter is genuinely good rather than a substring match, diacritic folding matters the moment you have non-English names, and remote data loading covers the case where options cannot live in the page. Against that, it is a fork, so bugs fixed in selectize upstream do not arrive here automatically, and the plugin API is a real commitment if you rely on it. Load it from a CDN to try it, then move to npm and a build if the project grows.

Frequently asked questions

How to use Tom Select?

Load the CSS and the complete JavaScript bundle, then pass a selector and a config object to the constructor, for example new TomSelect('#my-input', config). It can be loaded straight from jsDelivr or installed from npm with npm i tom-select.

What is the difference between the base and complete builds?

tom-select.complete.js includes dependencies and plugins, while tom-select.base.js does not include any plugins. There is also a popular entry point in the package exports map, and the base entry is the one to use if you have a bundle size budget.

How does Tom Select differ from selectize.js?

Tom Select was forked from selectize.js to modernize the codebase, remove the jQuery dependency, and expand functionality. Bug fixes made upstream in selectize do not automatically appear in Tom Select.

Does Tom Select handle loading options from a server?

Yes. Remote data loading is a core feature for when you have thousands of options and want them supplied by the server as the user types. Search ranking uses sifter to score and sort options on the fly across fields such as title and description.

Official sources

  1. License: Apache-2.0
  2. orchidjs/tom-select on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/orchidjs-tom-select.svg)](https://hysenlabs.com/projects/orchidjs-tom-select)