Tree Select

Component

Interactive examples and API documentation

Basic
Basic tree select with hierarchical options.
Select a region
Code
<% options = [
  {
    title: "Asia",
    key: "asia",
    children: [
      { title: "Japan", key: "japan" },
      { title: "Thailand", key: "thailand" }
    ]
  },
  {
    title: "Europe",
    key: "europe",
    children: [
      { title: "France", key: "france" },
      { title: "Italy", key: "italy" }
    ]
  }
] %>

<%= render Hakumi::TreeSelect::Component.new(
  name: "tree_select_basic",
  options: options,
  placeholder: "Select a region"
) %>
Multi-Level Nested
Tree with multiple levels of nesting (continent > country > state > city).
Select a location
Code
<%
  tree_options = [
    {
      title: "North America",
      key: "na",
      children: [
        {
          title: "United States",
          key: "us",
          children: [
            {
              title: "California",
              key: "ca",
              children: [
                { title: "Los Angeles", key: "la" },
                { title: "San Francisco", key: "sf" },
                { title: "San Diego", key: "sd" }
              ]
            },
            {
              title: "New York",
              key: "ny",
              children: [
                { title: "New York City", key: "nyc" },
                { title: "Buffalo", key: "buf" }
              ]
            },
            {
              title: "Texas",
              key: "tx",
              children: [
                { title: "Houston", key: "hou" },
                { title: "Austin", key: "aus" },
                { title: "Dallas", key: "dal" }
              ]
            }
          ]
        },
        {
          title: "Canada",
          key: "canada",
          children: [
            { title: "Toronto", key: "tor" },
            { title: "Vancouver", key: "van" },
            { title: "Montreal", key: "mon" }
          ]
        }
      ]
    },
    {
      title: "Europe",
      key: "eu",
      children: [
        {
          title: "United Kingdom",
          key: "uk",
          children: [
            { title: "London", key: "lon" },
            { title: "Manchester", key: "man" }
          ]
        },
        {
          title: "Germany",
          key: "de",
          children: [
            { title: "Berlin", key: "ber" },
            { title: "Munich", key: "mun" }
          ]
        }
      ]
    }
  ]
%>

<%= render Hakumi::TreeSelect::Component.new(
  name: "location",
  placeholder: "Select a location",
  tree_default_expand_all: true,
  allow_clear: true,
  options: tree_options
) %>
Multiple Selection
Allow selecting multiple nodes from the tree.
Select multiple countries
Code
<% options = [
  {
    title: "North America",
    key: "north-america",
    children: [
      { title: "USA", key: "usa" },
      { title: "Canada", key: "canada" }
    ]
  },
  {
    title: "South America",
    key: "south-america",
    children: [
      { title: "Brazil", key: "brazil" },
      { title: "Chile", key: "chile" }
    ]
  }
] %>

<%= render Hakumi::TreeSelect::Component.new(
  name: "tree_select_multiple",
  options: options,
  multiple: true,
  allow_clear: true,
  placeholder: "Select multiple countries"
) %>
Checkable
Tree with checkboxes for parent-child selection.
Check departments
Code
<% options = [
  {
    title: "Engineering",
    key: "engineering",
    children: [
      { title: "Frontend", key: "frontend" },
      { title: "Backend", key: "backend" }
    ]
  },
  {
    title: "Design",
    key: "design",
    children: [
      { title: "UX", key: "ux" },
      { title: "Visual", key: "visual" }
    ]
  }
] %>

<%= render Hakumi::TreeSelect::Component.new(
  name: "tree_select_checkable",
  options: options,
  tree_checkable: true,
  tree_default_expand_all: true,
  allow_clear: true,
  placeholder: "Check departments"
) %>
Searchable
Enable search to filter tree nodes.
Search and select
Code
<%= render Hakumi::TreeSelect::Component.new(
  name: "category",
  placeholder: "Search and select",
  show_search: true,
  tree_default_expand_all: true,
  options: [
    {
      title: "Electronics",
      key: "electronics",
      children: [
        { title: "Phones", key: "phones" },
        { title: "Laptops", key: "laptops" },
        { title: "Tablets", key: "tablets" }
      ]
    },
    {
      title: "Clothing",
      key: "clothing",
      children: [
        { title: "Shirts", key: "shirts" },
        { title: "Pants", key: "pants" },
        { title: "Shoes", key: "shoes" }
      ]
    }
  ]
) %>
Sizes
Three sizes: small, middle (default), and large.
Small
Middle (default)
Large
Code
<%
  tree_options = [
    {
      title: "Asia",
      key: "asia",
      children: [
        { title: "China", key: "china" },
        { title: "Japan", key: "japan" }
      ]
    },
    {
      title: "Europe",
      key: "europe",
      children: [
        { title: "Germany", key: "germany" },
        { title: "France", key: "france" }
      ]
    }
  ]
%>

<%= render Hakumi::Space::Component.new(direction: :vertical, size: :middle) do %>
  <%= render Hakumi::TreeSelect::Component.new(
    name: "small_select",
    placeholder: "Small",
    size: :small,
    options: tree_options
  ) %>

  <%= render Hakumi::TreeSelect::Component.new(
    name: "middle_select",
    placeholder: "Middle (default)",
    size: :middle,
    options: tree_options
  ) %>

  <%= render Hakumi::TreeSelect::Component.new(
    name: "large_select",
    placeholder: "Large",
    size: :large,
    options: tree_options
  ) %>
<% end %>
Leaf Only Selection
Only allow selecting leaf nodes (nodes without children).
Select product (leaf nodes only)
Code
<%
  tree_options = [
    {
      title: "Electronics",
      key: "electronics",
      children: [
        { title: "Phones", key: "phones" },
        { title: "Laptops", key: "laptops" },
        { title: "Tablets", key: "tablets" }
      ]
    },
    {
      title: "Clothing",
      key: "clothing",
      children: [
        { title: "Shirts", key: "shirts" },
        { title: "Pants", key: "pants" },
        { title: "Shoes", key: "shoes" }
      ]
    }
  ]
%>

<%= render Hakumi::TreeSelect::Component.new(
  name: "product",
  placeholder: "Select product (leaf nodes only)",
  tree_selectable_leaf_only: true,
  tree_default_expand_all: true,
  options: tree_options
) %>
Status
Error and warning status states.
Error status
Warning status
Code
<%
  tree_options = [
    {
      title: "Departments",
      key: "departments",
      children: [
        { title: "Engineering", key: "eng" },
        { title: "Marketing", key: "mkt" },
        { title: "Sales", key: "sales" }
      ]
    },
    {
      title: "Locations",
      key: "locations",
      children: [
        { title: "New York", key: "ny" },
        { title: "San Francisco", key: "sf" }
      ]
    }
  ]
%>

<%= render Hakumi::Space::Component.new(direction: :vertical, size: :middle) do %>
  <%= render Hakumi::TreeSelect::Component.new(
    name: "error_select",
    placeholder: "Error status",
    status: :error,
    options: tree_options
  ) %>

  <%= render Hakumi::TreeSelect::Component.new(
    name: "warning_select",
    placeholder: "Warning status",
    status: :warning,
    options: tree_options
  ) %>
<% end %>
Prefix
Add prefix icon or text to the selector.
Select with icon prefix
Region: Select with text prefix
Code
<%
  tree_options = [
    { title: "Asia", key: "asia", children: [
      { title: "Japan", key: "japan" },
      { title: "Thailand", key: "thailand" }
    ]},
    { title: "Europe", key: "europe", children: [
      { title: "France", key: "france" },
      { title: "Italy", key: "italy" }
    ]}
  ]
%>

<%= render Hakumi::Space::Component.new(direction: :vertical, size: :middle) do %>
  <%= render Hakumi::TreeSelect::Component.new(
    name: "location_icon",
    placeholder: "Select with icon prefix",
    prefix_icon: :environment,
    options: tree_options
  ) %>

  <%= render Hakumi::TreeSelect::Component.new(
    name: "location_text",
    placeholder: "Select with text prefix",
    prefix: "Region:",
    options: tree_options
  ) %>
<% end %>
Max Count
Limit the maximum number of selections.
Select up to 3 technologies
Code
<%
  tree_options = [
    {
      title: "Frontend",
      key: "frontend",
      children: [
        { title: "React", key: "react" },
        { title: "Vue", key: "vue" },
        { title: "Angular", key: "angular" }
      ]
    },
    {
      title: "Backend",
      key: "backend",
      children: [
        { title: "Node.js", key: "node" },
        { title: "Ruby", key: "ruby" },
        { title: "Python", key: "python" }
      ]
    },
    {
      title: "Mobile",
      key: "mobile",
      children: [
        { title: "React Native", key: "rn" },
        { title: "Flutter", key: "flutter" }
      ]
    }
  ]
%>

<%= render Hakumi::TreeSelect::Component.new(
  name: "frameworks",
  placeholder: "Select up to 3 technologies",
  tree_checkable: true,
  max_count: 3,
  tree_default_expand_all: true,
  options: tree_options
) %>
Borderless
Borderless variant for minimal styling.
Select file
Code
<%
  tree_options = [
    {
      title: "Documents",
      key: "docs",
      children: [
        { title: "Resume.pdf", key: "resume" },
        { title: "Cover Letter.pdf", key: "cover" }
      ]
    },
    {
      title: "Images",
      key: "images",
      children: [
        { title: "Photo.jpg", key: "photo" },
        { title: "Logo.png", key: "logo" }
      ]
    }
  ]
%>

<%= render Hakumi::TreeSelect::Component.new(
  name: "borderless_select",
  placeholder: "Select file",
  variant: :borderless,
  tree_default_expand_all: true,
  options: tree_options
) %>
Empty / No Data
Shows empty state when options is nil or empty array.
Options is nil
No Data
Options is empty array
No Data
Code
<%= render Hakumi::Space::Component.new(direction: :vertical, size: :middle) do %>
  <%= render Hakumi::TreeSelect::Component.new(
    name: "empty_nil",
    placeholder: "Options is nil",
    options: nil
  ) %>

  <%= render Hakumi::TreeSelect::Component.new(
    name: "empty_array",
    placeholder: "Options is empty array",
    options: []
  ) %>
<% end %>
Async Loading
Load children dynamically when expanding a node. Uses addNodes() and setLoading() API methods.
Expand nodes to load data
Code
<%
  # Initial options with async nodes (children will be loaded dynamically)
  tree_options = [
    {
      title: "Load Users",
      key: "users",
      async: true  # Mark as async - children will be loaded on expand
    },
    {
      title: "Load Products",
      key: "products",
      async: true
    },
    {
      title: "Load Empty (becomes leaf)",
      key: "empty",
      async: true  # Will receive empty array, becomes leaf
    },
    {
      title: "Load Error",
      key: "error",
      async: true  # Will simulate an error
    }
  ]
%>

<%= render Hakumi::TreeSelect::Component.new(
  name: "async_select",
  placeholder: "Expand nodes to load data",
  id: "async-tree-select",
  options: tree_options
) %>

<script>
document.addEventListener('DOMContentLoaded', function() {
  const treeSelect = document.getElementById('async-tree-select')

  // Simulated data that would come from an API
  const asyncData = {
    users: [
      { title: "John Doe", key: "user-1" },
      { title: "Jane Smith", key: "user-2" },
      { title: "Bob Johnson", key: "user-3" }
    ],
    products: [
      { title: "Laptop Pro", key: "prod-1" },
      { title: "Wireless Mouse", key: "prod-2" },
      { title: "USB-C Hub", key: "prod-3" }
    ],
    empty: [],  // Empty array - node will become a leaf
    error: null // Null simulates an error
  }

  // Listen for the load event from the Tree component inside TreeSelect
  treeSelect.addEventListener('hakumi--tree:load', function(event) {
    const { key } = event.detail
    const api = treeSelect.hakumiComponent?.api

    if (!api) return

    // Show loading state
    api.setLoading(key, true)

    // Simulate API call with timeout
    setTimeout(function() {
      const data = asyncData[key]

      if (data === null) {
        // Simulate error
        api.setError(key, true)
      } else {
        // Add nodes (if empty array, node becomes leaf automatically)
        api.addNodes(key, data)
        api.setLoading(key, false)
      }
    }, 1500)
  })
})
</script>

TreeSelect API

Prop Type Default Description
name String auto Name attribute for the hidden input.
options Array[Hash] [] Tree data with keys: key, title, children, disabled, selectable, checkable.
value String | Array - Selected value(s).
placeholder String "Select" Placeholder text.
multiple Boolean false Allow multiple selection.
tree_checkable Boolean false Show checkboxes for tree nodes.
show_search Boolean false Show search input in dropdown.
tree_default_expand_all Boolean false Expand all nodes by default.
tree_selectable_leaf_only Boolean false Only allow selecting leaf nodes.
disabled Boolean false Disable the select.
allow_clear Boolean false Show clear button.
size Symbol :middle Size: :small, :middle, :large.
variant Symbol :default Variant: :default, :borderless.
status Symbol - Status: :error, :warning.
max_count Integer - Maximum number of selections (multiple/checkable mode).
prefix String - Prefix text content.
prefix_icon Symbol - Prefix icon name.
required Boolean false Mark as required (shows asterisk).
label String - Form field label (when standalone: false).
caption String - Help text (when standalone: false).
errors Array [] Validation errors (when standalone: false).
standalone Boolean true Render without form item wrapper.

TreeSelect JavaScript API (element.hakumiComponent.api)

Prop Type Default Description
getValue() Function - Get selected value(s).
setValue(value) Function - Set selected value(s).
getLabel() Function - Get displayed label text.
open() Function - Open the dropdown.
close() Function - Close the dropdown.
toggle() Function - Toggle the dropdown.
isOpen() Function - Check if dropdown is open.
clear() Function - Clear selection.
focus() Function - Focus the selector.
blur() Function - Remove focus.
isDisabled() Function - Check if disabled.
getMaxCount() Function - Get max selection count.
isMaxReached() Function - Check if max selection count reached.
expandAll() Function - Expand all tree nodes.
collapseAll() Function - Collapse all tree nodes.
getExpandedKeys() Function - Get expanded node keys.
setExpandedKeys(keys) Function - Set expanded node keys.
addNodes(parentKey, nodes) Function - Add child nodes to a parent. If empty array, node becomes leaf.
setLoading(key, loading) Function - Set loading state on a node (shows spinner icon).
setError(key, error) Function - Set error state on a node (shows error styling).

Events

Prop Type Default Description
hakumi:tree-select:select CustomEvent - Triggered when selection changes. Detail: { value, label, values, labels, key }.
hakumi:tree-select:change CustomEvent - Triggered when value changes. Detail: { value, label, values, labels, key }.