
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, defaultfalse). Disables the component.id(String, default''). Sets the component ID.ariaLabel(String, default''). Sets the ARIA label.isSingleSelect(Boolean, defaultfalse). Uses one selected value and removes checkboxes.isGroupedValue(Boolean, defaultfalse). Returns selected group values when a whole group is selected.isIndependentNodes(Boolean, defaultfalse). Handles every node independently from parent and child selection state.rtl(Boolean, defaultfalse). Enables right-to-left mode.isBoostedRendering(Boolean, defaultfalse). Uses experimental visibility-based rendering for large lists.
Dropdown list options
disabledBranchNode(Boolean, defaultfalse). Limits selection to leaf nodes.openLevel(Number, default0). Opens groups through the specified tree depth.appendToBody(Boolean, defaultfalse). Appends the dropdown list tobody.alwaysOpen(Boolean, defaultfalse). Keeps the dropdown list open.showCount(Boolean, defaultfalse). Displays child counts beside group names.staticList(Boolean, defaultfalse). 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, defaultnull). Appends a custom element to the end of the list.direction(String, default'auto'). Acceptsauto,top, orbottom.expandSelected(Boolean, defaultfalse). Opens groups that contain selected values during initialization.saveScrollPosition(Boolean, defaulttrue). 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, defaulttrue). 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, defaultnull). Defines the sort order for selected tags.clearable(Boolean, defaulttrue). Displays the clear control.searchable(Boolean, defaulttrue). Enables text search.placeholder(String, default'Search...'). Sets the input placeholder.grouped(Boolean, defaulttrue). 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: '×'
}
})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, defaulttrue). 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
- Filterable & Checkable Multi-Select Dropdown In JavaScript
- 10 Best Tree View JavaScript Libraries
- Multi-Select Drop Down Tree Plugin With jQuery – Combo Tree
- Hierarchical Data Display with Shadcn/ui Tree View
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.







