Tree
The tree organizes data into a tree-like structure with collapsible and expandable nodes. It allows users to navigate complex hierarchical information, such as directories and categories. The component typically includes parent and child nodes, where parent nodes can be expanded to reveal their children.
<sl-tree id="tree" aria-label="Subjects structure"></sl-tree>
<script type="module">
  import { FlatTreeDataSource } from '@sl-design-system/tree';
  const tree = document.querySelector('#tree');
  const flatData = [
    { id: 0, expandable: true, level: 0, name: 'Mathematics' },
    { id: 1, expandable: true, level: 1, name: 'Algebra' },
    { id: 2, expandable: false, level: 2, name: 'Lesson 1 - Linear equations.md' },
    { id: 3, expandable: false, level: 2, name: 'Lesson 2 - Quadratic equations.md' },
    { id: 4, expandable: true, level: 1, name: 'Geometry' },
    ...
    { id: 18, expandable: true, level: 1, name: 'Modern History' },
    { id: 19, expandable: false, level: 2, name: 'World War I.md' },
    { id: 20, expandable: false, level: 2, name: 'World War II.md' }
  ];
  const dataSource = new FlatTreeDataSource(flatData, {
    getId: (item) => item.id,
    getLabel: ({ name }) => name,
    getLevel: ({ level }) => level,
    isExpandable: ({ expandable }) => expandable,
    isExpanded: ({ name }) => ['Mathematics', 'Algebra'].includes(name),
    isSelected: ({ id }) => [2, 3, 12].includes(id),
    multiple: true
  });
  tree.dataSource = dataSource;
</script>When to use
The following guidance describes when to use the tree component.
Hierarchical Content
The Tree is ideal for displaying and navigating hierarchical data, such as file systems or category structures. It groups related data with nested relationships in a clear and organized way. It is a powerful tool for organizing subject lesson content in educational applications. For example, it represents a syllabus with modules as parent nodes and lessons as child nodes, enabling students to intuitively explore and navigate their coursework.
Collapsible Data
The Tree allows users to dynamically expand or collapse data sections, enabling a cleaner interface that focuses only on relevant information. This interactive functionality is handy when managing large amounts of content, where each item contains complex data or detailed information. It ensures users can explore deeply without being overwhelmed.
When not to use
Global Navigation
Do not use Tree as the primary navigation for your product’s UI. The tree component is not suitable for this purpose.
Elements Toggle
The tree is not ideal for showing and hiding UI elements or content within a page. If the interaction only involves collapsing or expanding content at a basic level, consider using other components like accordions or collapsible panels for a more straightforward solution.
Anatomy
| Item | Name | Description | Optional | 
|---|---|---|---|
| 1 | Title | The main text label of the node, representing the name or identifier of the item in the hierarchy. | no | 
| 2 | Toggle | An interactive element that allows users to expand or collapse child nodes under the parent node. | Yes | 
| 3 | Icon | A visual indicator representing the type or state of the node. | Yes | 
| 4 | Checkbox | A selectable option that allows users to select or deselect nodes. | Yes | 
| 5 | Guide Lines | Visual lines used to indicate the hierarchical structure of the tree. | Yes | 
| 6 | Indentation | The visual offset of child nodes to indicate their relationship with parent nodes. | Yes | 
Variants
Tree comes in three versions, each suited for specific situations:
Node
A basic element in the tree, representing a terminal item without parent or child nodes.
Parent Node
A node that has one or more child nodes, typically expandable to reveal more detailed data.
Child Node
A node nested under a parent node, typically hidden until the parent is expanded, representing more detailed or lower-level information.
Figma Options
With these options, you can tweak the appearance of the Tree in Figma. They are available in the Design Panel so you can compose the switch to exactly fit the user experience need for the use case you are working on.
| Item | Options | Description | 
|---|---|---|
| Variant | 'Child', 'Parent' | Defines whether the node behaves as a parent with expandable content or a child item. | 
| Expanded | 'on', 'off' | Toggles whether the parent node is expanded to show its children. | 
| Multiselect | 'on', 'off' | Enables the ability to select multiple nodes at once. | 
| Selected | 'on', 'off' | Indicates whether the node is currently selected. | 
| Node Label | Text | The text label displayed as the node’s title. | 
| Icon | 'on', 'off' | Shows or hides the icon associated with the node (e.g., folder, file). | 
| showFocus | 'on', 'off' | Displays a focus ring around the node when active. | 
| Level | '1' to '6' | Sets the hierarchy level to control indentation. | 
| hideGuides | 'on', 'off' | Shows or hides the connector guides between parent and child nodes. | 
| Actions Type | 'Badge', 'Button Bar' | Toggles additional actions available on the node (e.g., edit, delete). | 
| State | 'idle', 'hover', 'active' | Represents the interactive state of the node (e.g., default, hover). | 
| Selected | 'on', 'off' | Indicates if the node is selected in its current state. | 
Behaviour
Let's explore the behaviour of the Tree.
Selectable
When this feature is enabled, nodes can be selected by the user, allowing for interactions such as checking, highlighting, or performing actions on a specific node.
Multiple Selection
When this feature is enabled, users can select multiple nodes at the same time, allowing interactions such as checking, highlighting, or performing actions on several nodes simultaneously. Single selection is disabled in this mode to simplify user interaction.
Expandable
Allowing users to click on a parent node to reveal its child nodes. This interaction helps in navigating deeper structures without overwhelming the user with too much data at once. It is essential for managing large hierarchical datasets.
Indentation
Indentation visually distinguishes parent nodes from their child nodes by shifting them to the right. This hierarchy helps users understand the relationship between different levels of the data quickly.
Related Components
<sl-tree aria-label="Files structure"></sl-tree>
<script type="module">
  import { html, nothing } from 'lit';
  import { FlatTreeDataSource } from '@sl-design-system/tree';
  const flatData = [
    { id: 0, expandable: true, level: 0, name: 'textarea' },
    { id: 1, expandable: false, level: 1, name: 'package.json' },
    { id: 2, expandable: true, level: 0, name: 'tree' },
    { id: 3, expandable: true, level: 1, name: 'src' },
    { id: 4, expandable: false, level: 2, name: 'tree-node.ts' }
  ];
  const dataSource = new FlatTreeDataSource(flatData, {
    getIcon: ({ name }, expanded) =>
      name.includes('.') ? 'far-file-lines' : `far-folder${expanded ? '-open' : ''}`,
    getId: (item) => item.id,
    getLabel: ({ name }) => name,
    getLevel: ({ level }) => level,
    isExpandable: ({ expandable }) => expandable,
    isExpanded: ({ name }) => ['tree', 'src'].includes(name)
  });
  const renderer = (node) => {
    const icon = node.label.includes('.') ? 'far-file-lines' : `far-folder${node.expanded ? '-open' : ''}`;
    const onClickEdit = (event) => event.stopPropagation();
    const onClickRemove = (event) => event.stopPropagation();
    return html`
      ${icon ? html`<sl-icon size="sm" .name=${icon}></sl-icon>` : nothing}
      <span>${node.label}</span>
      <sl-button @click=${onClickEdit} aria-label="Edit" slot="actions">
        <sl-icon name="far-pen"></sl-icon>
      </sl-button>
      <sl-button @click=${onClickRemove} aria-label="Remove" slot="actions"s>
        <sl-icon name="far-trash"></sl-icon>
      </sl-button>
    `;
  }
  const tree = document.querySelector('sl-tree');
  tree.dataSource = dataSource;
  tree.renderer = renderer;
</script>
Tree data source
The tree component requires a data source to supply structure and manage state. This component provides FlatTreeDataSource, which adapts a flat array to a hierarchical view, and NestedTreeDataSource, which works directly with nested tree-structured data.
What is a data source?
A data source is an adapter that normalizes your raw data into the view model that UI components use. It centralizes filtering, sorting, selection, and emits events when its state changes. Multiple components (e.g. tree, grid, paginator) share the same base DataSource so behaviour stays consistent.
For tree, FlatTreeDataSource extends the base and maps a flat array with a level field into a hierarchical view while tracking expansion and selection. Alternatively, you can use NestedTreeDataSource if your data is already structured as a nested tree, allowing you to work directly with hierarchical data without flattening it first. Both extend the base TreeDataSource.
Both tree data sources do not enforce a specific data shape. Instead, you provide callback functions to extract ids, labels, levels, children, and expansion state from your items. The data source will use these callbacks to build the tree structure and manage state.
export interface TreeDataSourceMapping<T> {
  /** Optional method for returning a custom aria description for a tree node. */
  getAriaDescription?(item: T): string | undefined;
  /**
   * Returns the number of children. This can be used in combination with
   * lazy loading children. This way, the tree component can show skeletons
   * for the children while they are being loaded.
   */
  getChildrenCount?(item: T): number | undefined;
  /** Optional method for returning a custom icon for a tree node. */
  getIcon?(item: T, expanded: boolean): string;
  /** Used to identify a tree node. */
  getId(item: T): unknown;
  /**
   * Returns a string that is used as the label for the tree node.
   * If you want to customize how the tree node is rendered, you can
   * provide your own `TreeItemRenderer` function to the tree component.
   */
  getLabel(item: T): string;
  /** Returns whether the given node is expandable. */
  isExpandable(item: T): boolean;
  /**
   * Returns whether the given node is expanded. This is only used for the initial
   * expanded state of the node. If you want to expand/collapse a node programmatically,
   * use the `expand` and `collapse` methods on the data source.
   */
  isExpanded?(item: T): boolean;
  /**
   * Returns whether the given node is selected. This is only used for the initial
   * selected state of the node. If you want to select/deselect a node programmatically,
   * use the `select` and `deselect` methods on the data source.
   */
  isSelected?(item: T): boolean;
}Depending on whether you use FlatTreeDataSource or NestedTreeDataSource, you will need to provide additional mapping functions:
export interface FlatTreeDataSourceMapping<T> extends TreeDataSourceMapping<T> {
  /** Returns the level in the tree of the given item. */
  getLevel(item: T): number;
}or
export interface NestedTreeDataSourceMapping<T> extends TreeDataSourceMapping<T> {
  /** Returns the children of the given item. */
  getChildren(item: T): T[] | Promise<T[]> | undefined;
}Custom renderer
The tree component renders the tree nodes by default using the label and icon provided by the data source. It does this using a virtual list, so it can efficiently render large trees. This also means that you cannot use regular slot-based templating to customize the rendering of tree nodes.
The tree component provides a renderer callback function that supports custom rendering of nodes. This allows you to add custom icons, buttons, or other interactive elements to each node.
const renderer = node => {
  // Don't show action buttons for expandable nodes; returning undefined
  // will make the tree use the default rendering.
  if (node.expandable) {
    return undefined;
  }
  const onClick = (event: Event) => event.stopPropagation();
  return html`
    <span>${node.label}</span>
    <sl-button @click=${onClick} aria-label="Edit" slot="actions">
      <sl-icon name="far-pen"></sl-icon>
    </sl-button>
    <sl-button @click=${onClick} aria-label="Remove" slot="actions">
      <sl-icon name="far-trash"></sl-icon>
    </sl-button>
  `;
};Do not forget to specify any scoped elements you use in your renderer in the scopedElements property of the <sl-tree> component.
const tree = document.querySelector('sl-tree');
tree.renderer = renderer;
tree.scopedElements = { 'sl-button': Button };Some, such as <sl-icon>, are already included by default.
API
The tree API exposes a comprehensive set of properties, events, and customization options, enabling developers to tailor its behavior, appearance, and interaction patterns for diverse use cases.
Properties
| Name | Attribute | Type | Default | Description | 
|---|---|---|---|---|
| dataSource | - | TreeDataSource<T> | undefined | The model for the tree. | |
| hideGuides | hide-guides | boolean | undefined | Hides the indentation guides when set. | |
| renderer | - | TreeItemRenderer<T> | undefined | Custom renderer function for tree items. | |
| scopedElements | - | Record<string, typeof HTMLElement> | undefined | The custom elements used for rendering this tree. If you are using a custom renderer to render the tree nodes, any custom elements you use in the renderer need to be specified via this property. Otherwise those custom elements will not initialize, since the tree uses a Scoped Custom Element Registry. | 
Events
| Name | Event type | Description | 
|---|---|---|
| sl-select | SlSelectEvent<TreeDataSourceNode<T>> | Emits when the user selects a tree node. | 
Keyboard interactions
| Command | Description | 
|---|---|
| Tab | Moves focus into the tree (to the first selected node, or the first visible node) or to the next focusable element when leaving the tree. Inline action controls inside a node are tabbable. | 
| Shift + Tab | Moves focus to the previous focusable element (can move focus out of the tree). | 
| Arrow Down | Moves focus to the next visible node. | 
| Arrow Up | Moves focus to the previous visible node. | 
| Arrow Right | On a collapsed, expandable node: expands it and keeps focus. On an expanded node: moves focus to its first child. | 
| Arrow Left | On an expanded node: collapses it and keeps focus. On a leaf node (the nodes which don't have any child nodes are called leaf nodes): moves focus to its parent. | 
| Home | Moves focus to the first visible node. | 
| End | Moves focus to the last visible node. | 
| Enter / Space | Selects or toggles selection of the focused node. | 
WAI-ARIA
In the component itself we use multiple aria-attributes to assure the component works well with a range of assistive technologies. For some attributes however it is not possible for the Design System to add a meaningful value, because it relies on the context or way a component is used.
Attributes that we recommend you add in certain scenarios are mentioned below.
Tree
| Attribute | Value | Description | 
|---|---|---|
| aria-label | string | Accessible name for the sl-tree. | 
| aria-labelledby | string | References (via id) a visible element that labels the tree (e.g. a heading). |