Treeselect JS: Tree Select & Multi-Select Dropdown in Vanilla JavaScript

Category: Form , Javascript | August 25, 2026
Authordipson88
Last UpdateAugust 25, 2026
LicenseMIT
Views25,807 views
Treeselect JS: Tree Select & Multi-Select Dropdown in Vanilla JavaScript

Treeselect JS is a vanilla JavaScript and TypeScript tree select component that creates nested options inside a searchable dropdown. Your users can browse hierarchical groups, search nodes, and choose one or multiple values from the same control.

The core treeselectjs package supports ES modules and a UMD browser build. React and Vue 3 wrappers are available as react-treeselectjs and vue-treeselectjs.

Features

  • Searchable tree select dropdown for nested options.
  • Checkbox multi-select and single-select modes.
  • Tags, grouped values, child counts, and selectable groups.
  • Keyboard controls for arrows, Space, and Enter.
  • Automatic, top, or bottom dropdown direction.
  • RTL mode and configurable ARIA label.
  • Optional boosted rendering for large option trees.
  • CSS custom properties for component colors.
  • React and Vue 3 wrapper packages.

How to use Treeselect JS

Install with npm

Install the core package for ES module projects, then import the JavaScript module and stylesheet.

npm install --save treeselectjs
import Treeselect from 'treeselectjs'
import 'treeselectjs/dist/treeselectjs.css'

Load Treeselect JS from a CDN

The UMD build exposes Treeselect as a browser global. Load the stylesheet and UMD file before creating the component.

<link rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/treeselectjs/dist/treeselectjs.css">
<script src="https://cdn.jsdelivr.net/npm/treeselectjs/dist/treeselectjs.umd.js"></script>

Basic tree select dropdown

Create a container element, define nested options, and pass both to the Treeselect constructor. Every node needs a unique value.

<div id="product-tree"></div>
const productOptions = [
  {
    name: 'Hardware',
    value: 'hardware',
    children: [
      {
        name: 'Laptops',
        value: 'laptops',
        children: []
      },
      {
        name: 'Monitors',
        value: 'monitors',
        children: []
      }
    ]
  },
  {
    name: 'Software',
    value: 'software',
    children: [
      {
        name: 'Design Tools',
        value: 'design-tools',
        children: []
      },
      {
        name: 'Developer Tools',
        value: 'developer-tools',
        children: []
      }
    ]
  }
]
const productTree = new Treeselect({
  parentHtmlContainer: document.querySelector('#product-tree'),
  options: productOptions,
  value: ['laptops']
})

Use Treeselect as a single-select tree dropdown

Set isSingleSelect to true for one selected node. Pass one string or number as the selected value. showTags: false keeps the input closer to a standard dropdown.

<div id="category-tree"></div>
const categoryTree = new Treeselect({
  parentHtmlContainer: document.querySelector('#category-tree'),
  options: productOptions,
  value: 'design-tools',
  isSingleSelect: true,
  showTags: false
})

Improve rendering for large trees

isBoostedRendering is an experimental option for large trees that encounter rendering performance problems. It uses visibility-based rendering with IntersectionObserver. In this snippet, largeOptionSet represents your existing options array.

<div id="large-tree"></div>
const largeTree = new Treeselect({
  parentHtmlContainer: document.querySelector('#large-tree'),
  options: largeOptionSet,
  isBoostedRendering: true
})

Configuration options

Core options

  • parentHtmlContainer (HTMLElement, required). Container used to render the component.
  • value (Array<String | Number>, default []). Selected node values for multi-select mode.
  • options (Array<Object>, default []). Hierarchical option data.
  • disabled (Boolean, default false). Disables the component.
  • id (String, default ''). Sets the component ID.
  • ariaLabel (String, default ''). Sets the ARIA label.
  • isSingleSelect (Boolean, default false). Uses one selected value and removes checkboxes.
  • isGroupedValue (Boolean, default false). Returns selected group values when a whole group is selected.
  • isIndependentNodes (Boolean, default false). Handles every node independently from parent and child selection state.
  • rtl (Boolean, default false). Enables right-to-left mode.
  • isBoostedRendering (Boolean, default false). Uses experimental visibility-based rendering for large lists.

Dropdown list options

  • disabledBranchNode (Boolean, default false). Limits selection to leaf nodes.
  • openLevel (Number, default 0). Opens groups through the specified tree depth.
  • appendToBody (Boolean, default false). Appends the dropdown list to body.
  • alwaysOpen (Boolean, default false). Keeps the dropdown list open.
  • showCount (Boolean, default false). Displays child counts beside group names.
  • staticList (Boolean, default false). Renders the list as a static DOM element that occupies layout space.
  • emptyText (String, default 'No results found...'). Text shown for an empty filtered list.
  • listSlotHtmlComponent (HTMLElement, default null). Appends a custom element to the end of the list.
  • direction (String, default 'auto'). Accepts auto, top, or bottom.
  • expandSelected (Boolean, default false). Opens groups that contain selected values during initialization.
  • saveScrollPosition (Boolean, default true). Restores the previous list scroll position after reopening.
  • listClassName (String, default ''). Applies custom class names to the dropdown list.

Input and tag options

  • showTags (Boolean, default true). Displays selected values as tags.
  • tagsCountText (String, default 'elements selected'). Sets the text shown after the selected count when tags are hidden.
  • tagsSortFn (Function | null, default null). Defines the sort order for selected tags.
  • clearable (Boolean, default true). Displays the clear control.
  • searchable (Boolean, default true). Enables text search.
  • placeholder (String, default 'Search...'). Sets the input placeholder.
  • grouped (Boolean, default true). Groups selected leaf nodes under their parent when the full group is selected.

Callback options

  • inputCallback. Runs when the selected value changes.
  • openCallback. Runs when the dropdown opens.
  • closeCallback. Runs when the dropdown closes.
  • nameChangeCallback. Runs when the selected name shown in the input changes.
  • searchCallback. Receives the current search string while the user types.
  • openCloseGroupCallback. Receives the group value and open or closed state after a group toggle.

Custom icons

iconElements accepts replacements for the built-in SVG icons. Available keys are arrowUp, arrowDown, arrowRight, attention, clear, cross, check, and partialCheck.

<div id="icon-tree"></div>
const iconTree = new Treeselect({
  parentHtmlContainer: document.querySelector('#icon-tree'),
  options: productOptions,
  iconElements: {
    clear: '&times;'
  }
})

Tree option structure

Each item in the options array uses the fields below. Node values must be unique, while node names can repeat.

  • value (String | Number, required). Unique value for the node.
  • name (String, required). Visible node label.
  • disabled (Boolean, optional). Disables the node.
  • htmlAttr (Object, optional). Applies string-valued HTML attributes to the node element.
  • isGroupSelectable (Boolean, optional, default true). Controls selection for group nodes.
  • children (Array). Nested nodes that use the same data structure.

Events

The core component dispatches events through treeselect.srcElement. Read event data from event.detail.

// Fires when the selected value changes.
treeselect.srcElement.addEventListener('input', (event) => {
  console.log(event.detail)
})
// Fires when the dropdown opens.
treeselect.srcElement.addEventListener('open', (event) => {
  console.log(event.detail)
})
// Fires when the dropdown closes.
treeselect.srcElement.addEventListener('close', (event) => {
  console.log(event.detail)
})
// Fires when the selected name changes.
treeselect.srcElement.addEventListener('name-change', (event) => {
  console.log(event.detail)
})
// Fires while the search text changes.
treeselect.srcElement.addEventListener('search', (event) => {
  console.log(event.detail)
})
// Fires after a group opens or closes.
treeselect.srcElement.addEventListener('open-close-group', (event) => {
  console.log(event.detail)
})

API methods

Treeselect exposes five public methods for value updates, remounting, focus control, dropdown state, and cleanup.

// Update selected values.
treeselect.updateValue(['laptops', 'design-tools'])
// Rebuild the component after changing instance settings.
treeselect.mount()
// Focus the input and keep the current open or closed state.
treeselect.focus()
// Open or close the dropdown and focus the input.
treeselect.toggleOpenClose()
// Remove the rendered component from the DOM.
treeselect.destroy()

Customize Treeselect JS with CSS variables

Treeselect JS defines its color variables on :root. When appendToBody is active, override the variables on :root or body. The dropdown list is rendered under body in this mode. Define only the variables your theme needs to change.

  • --treeselectjs-border-color (#d7dde4). Input and list border.
  • --treeselectjs-bg (#ffffff). Input background.
  • --treeselectjs-border-focus (#101010). Focused border.
  • --treeselectjs-tag-bg (#d7dde4). Selected tag background.
  • --treeselectjs-tag-bg-hover (#c5c7cb). Tag hover background.
  • --treeselectjs-tag-remove-hover (#eb4c42). Tag remove icon hover color.
  • --treeselectjs-icon (#c5c7cb). Arrow and clear icon color.
  • --treeselectjs-icon-hover (#838790). Icon hover color.
  • --treeselectjs-item-counter (#838790). Group count text.
  • --treeselectjs-item-focus-bg (#f0ffff). Focused list item background.
  • --treeselectjs-item-selected-bg (#e9f1f1). Selected list item background.
  • --treeselectjs-item-disabled-text (#c5cbca). Disabled item text.
  • --treeselectjs-checkbox-bg (#ffffff). Checkbox background.
  • --treeselectjs-checkbox-border-color (#d7dde4). Checkbox border.
  • --treeselectjs-checkbox-checked-bg (#52c67e). Checked checkbox background.
  • --treeselectjs-checkbox-checked-icon (#ffffff). Checkmark color.
:root {
  --treeselectjs-border-color: #cbd5e1;
  --treeselectjs-bg: #ffffff;
  --treeselectjs-border-focus: #2563eb;
  --treeselectjs-tag-bg: #dbeafe;
  --treeselectjs-tag-bg-hover: #bfdbfe;
  --treeselectjs-item-focus-bg: #eff6ff;
  --treeselectjs-item-selected-bg: #dbeafe;
  --treeselectjs-checkbox-checked-bg: #2563eb;
}

React and Vue tree select wrappers

React projects use react-treeselectjs. Vue 3 projects use vue-treeselectjs. Both packages wrap the Treeselect JS core library and ship their own stylesheets.

# React
npm install --save react-treeselectjs
# Vue 3
npm install --save vue-treeselectjs

Alternatives and related resources

FAQs

Q: Can Treeselect JS work as a single-select dropdown?
A: Yes. Set isSingleSelect to true and pass one string or number as the selected value. Set showTags to false for a compact dropdown-style input.

Q: How do I style the dropdown when appendToBody is enabled?
A: Override the --treeselectjs-* variables on :root or body. The list is appended under body in this mode.

Q: What should I check when duplicate option errors appear?
A: Check every node’s value. Each value must be unique across the tree, while display names can repeat.

Q: How can I handle a very large option tree?
A: Try isBoostedRendering: true if normal list rendering becomes slow. This experimental mode uses visibility-based rendering with IntersectionObserver.

Changelog:

08/25/2026

  • Update

v0.14.1 (02/27/2026)

  • Move CSS variables to :root.
  • Change CSS variable names from –treeselect to –treeselectjs for better consistency and clarity.

v0.14.0 (02/27/2026)

  • add CSS color variables for better customization.
  • decrease bundle size.

v0.13.3 (12/19/2025)

  • add an opportunity to use multiple classes support for the listClassName prop.

v0.13.2 (11/26/2025)

  • Fix shadow root issues

v0.13.1 (04/12/2025)

  • Fix slot blur event ignore in Firefox and Safari.

v0.13.0 (03/06/2025)

  • Increase list component performance.
  • Add isBoostedRendering prop.
  • Add isGroupSelectable field to the options prop.

v0.12.3 (03/06/2025)

  • Provide an opportunity to overwrite the title attribute for options with the help of the htmlAtt field.

v0.12.2 (03/04/2025)

  • Add type TagsSortFnType and type TagsSortItem to the export

v0.12.1 (02/22/2025)

  • Add tagsSortFn property

v0.12.0 (01/13/2025)

  • Add 0 as a valid value to the options values.

v0.11.0 (06/17/2024)

  • Add a listClassName prop.

v0.10.0 (11/19/2023)

  • Add RTL mode prop (rlt).

v0.9.3 (09/24/2023)

  • Add open-close-group event and openCloseGroupCallback prop.

v0.9.1 (07/11/2023)

  • Add ariaLabel attribute for the accessibility. Prop uses placeholder as a default value.

v0.9.0 (06/06/2023)

  • Add isIndependentNodes prop
  • Add ‘search’ event
  • Add searchCallback prop

v0.8.6 (04/19/2023)

  • Add info about Vue wrapper.

v0.8.5 (04/18/2023)

  • Bugfix

v0.8.4 (04/16/2023)

  • Bugfix

v0.8.2 (04/16/2023)

  • Add info about react wrapper.

v0.8.1 (04/14/2023)

  • Add export for major types.

v0.8.0 (04/12/2023)

  • Add vite and remove parcel.
  • Add umd file.

v0.7.0 (03/27/2023)

  • Fix: public filed value contains a currently selected value.
  • Add a disabled field to the options array.
  • Add the htmlAttr field to the list item.
  • Add expandSelected prop.
  • Add saveScrollPosition prop.
  • Improve cursor behavior during searchable actions.

v0.6.0 (03/20/2023)

  • Bugfixes

v0.5.8 (01/30/2023)

  • Fix: remove global variable for single-select.

v0.5.7 (12/16/2022)

  • Add preventing of scripts in names.

v0.5.6 (11/03/2022)

  • Fix nameChangeCallback empty name.
  • Add read-only attribute for unsearchable mode. Hide keyboard for mobile devices.
  • Remove empty id from input element.
  • Fix the scroll position during key navigation with the slot.

v0.5.5 (11/01/2022)

  • Add selectedName field to the Treeselect class.

v0.5.4 (11/01/2022)

  • Fix: parent node selects for isSingleSelect mode if a parent has only one child node.
  • Add nameChangeCallback method.

v0.5.3 (10/15/2022)

  • Add class is-single-select to the input.
  • Add overflow to the placeholder.

v0.5.2 (10/04/2022)

  • Add text align for labels and checkbox icons.

v0.5.1 (10/03/2022)

  • Fix disabled prop resetting.
  • Fix direction prop wrong validation.

v0.5.0 (09/30/2022)

  • Added Direction prop
  • Added openCallback
  • Added closeCallback

v0.4.3 (09/08/2022)

  • Fix focus/blur behavior for visibility/display style changes.

v0.4.2 (09/06/2022)

  • Add isGroupedValue prop.
  • Add disabledBranchNode prop.
  • Add title to the selected value in isSingleSelect mode.
  • Add styles for selected value inside the list.
  • Fix tab navigation bug. (You couldn’t unfocus element).

v0.4.1 (09/05/2022)

  • Fix keyboard focus issues.
  • Add prevent enter key for correct forms work.

v0.4.0 (09/05/2022)

  • Add isSingleSelect prop.
  • Add showCount prop.
  • Rename main files form treeslecet-js to treeselectjs.

v0.3.6 (08/24/2022)

  • Remove invisible input line for unsearchable mode.
  • Swap event listeners with callbacks.
  • Move Input element to the tags list.
  • Unsearchable mode input fix.

v0.3.3 (07/29/2022)

  • Remove swc/helpers dependency.

v0.3.2 (07/28/2022)

  • added dependency

v0.3.1 (07/23/2022)

  • Typescript support.
  • New props were added: id, iconElements, inputCallback.
  • ES modules and CommonJS support were added.
  • Ability to use numbers as value.
  • iconElements – Now we can create a component to reset default icons.
  • Code refactoring.
  • Build with browserlist (“> 0.5%, last 2 versions, not dead”).
  • Package size was minimized.

v0.2.9 (07/07/2022)

  • Add tagsCountText prop.
  • Fix the wrong input value if the user tries to remove the tag from input.
  • Add toggleOpenClose and focus methods.

v0.2.8 (07/02/2022)

  • Bug Fixes

v0.2.7 (06/30/2022)

  • Add staticList prop.
  • Fix resize bug for the appendToBody prop.
  • Fix code misspellings.

v0.2.6 (06/29/2022)

  • Fix: a bug that is related to the wrong partial checkbox check.
  • Method for the list position was updated.
  • Fix: a bug related to the wrong position for the list on blur if alwaysOpen prop is selected.
  • Added validation message for duplicate values.

You Might Be Interested In:


Leave a Reply