Tree

PRO

Expand and explore a hierarchy, then select or edit items.

Live preview
Interact with the component to see results here.
View code
HTML
<sy-tree
  expandable
  checkable
  clickable
  searchterm=""
  id="sample"
></sy-tree>

<script type="module">
  const component1 = document.querySelector("#sample");
  Object.assign(component1, {
    "nodes": [{
        "value": "project",
        "label": "Project",
        "expanded": true,
        "appendable": true,
        "children": [{
            "value": "core",
            "label": "Design System",
            "editable": true,
            "removable": true
          },
          {
            "value": "charts",
            "label": "Charts",
            "editable": true,
            "removable": true
          },
          {
            "value": "grid",
            "label": "Grid",
            "disabled": true
          }
        ]
      },
      {
        "value": "docs",
        "label": "Documents",
        "appendable": true,
        "children": [{
          "value": "guide",
          "label": "Guide"
        }]
      }
    ]
  });
</script>

Usage guide

#

Use to explore and manage hierarchical data, such as files or organizations. Use Tree Select to collect a value in a form.

  1. Build the tree

    Provide unique value identifiers, label, and children in nodes.

  2. Set the interaction scope

    Enable expandable, clickable, or checkable, and further restrict interactions on individual nodes.

  3. Save changes

    Handle nodesChanged and save in your app. Example changes affect only the local view.

Examples

#

Hierarchy navigation

Expand a parent to see its children.

View code
HTML
<sy-tree
  expandable
  clickable
  id="sample"
></sy-tree>

<script type="module">
  const component1 = document.querySelector("#sample");
  Object.assign(component1, {
    "nodes": [{
        "value": "project",
        "label": "Project",
        "expanded": true,
        "appendable": true,
        "children": [{
            "value": "core",
            "label": "Design System",
            "editable": true,
            "removable": true
          },
          {
            "value": "charts",
            "label": "Charts",
            "editable": true,
            "removable": true
          },
          {
            "value": "grid",
            "label": "Grid",
            "disabled": true
          }
        ]
      },
      {
        "value": "docs",
        "label": "Documents",
        "appendable": true,
        "children": [{
          "value": "guide",
          "label": "Guide"
        }]
      }
    ]
  });
</script>

Hierarchical checking

Parent and child checked states are linked.

View code
HTML
<sy-tree
  expandable
  checkable
  id="sample"
></sy-tree>
<div class="demo-actions"
  style="display:flex;flex-wrap:wrap;gap:8px;margin-top:16px"
>
  <sy-button id="action-0" size="small">Check Design System</sy-button>
  <sy-button id="action-1" size="small">Uncheck</sy-button>
</div>
<output id="demo-result" aria-live="polite"></output>

<script type="module">
  const describeResult = value => JSON.stringify(value, (_key, item) => {
    if (item instanceof File) return {
      name: item.name,
      size: item.size,
      type: item.type
    };
    if (item instanceof Element) return `<${item.localName}>`;
    return item;
  }) ?? 'Done';
  const component1 = document.querySelector("#sample");
  Object.assign(component1, {
    "nodes": [{
        "value": "project",
        "label": "Project",
        "expanded": true,
        "appendable": true,
        "children": [{
            "value": "core",
            "label": "Design System",
            "editable": true,
            "removable": true
          },
          {
            "value": "charts",
            "label": "Charts",
            "editable": true,
            "removable": true
          },
          {
            "value": "grid",
            "label": "Grid",
            "disabled": true
          }
        ]
      },
      {
        "value": "docs",
        "label": "Documents",
        "appendable": true,
        "children": [{
          "value": "guide",
          "label": "Guide"
        }]
      }
    ]
  });
  const actionTarget0 = document.querySelector("#sample");
  document.querySelector('#action-0').addEventListener('click', async () => {
    const result = await actionTarget0.setCheckState("core", true);
    document.querySelector('#demo-result').textContent = describeResult(result);
  });
  const actionTarget1 = document.querySelector("#sample");
  document.querySelector('#action-1').addEventListener('click', async () => {
    const result = await actionTarget1.clearAllSelectedItem();
    document.querySelector('#demo-result').textContent = describeResult(result);
  });
</script>

Add, edit, and remove

Only actions allowed on the node are shown. Refresh to restore the original example.

View code
HTML
<sy-tree
  expandable
  editable
  expandall
  id="sample"
></sy-tree>

<script type="module">
  const component1 = document.querySelector("#sample");
  Object.assign(component1, {
    "nodes": [{
        "value": "project",
        "label": "Project",
        "expanded": true,
        "appendable": true,
        "children": [{
            "value": "core",
            "label": "Design System",
            "editable": true,
            "removable": true
          },
          {
            "value": "charts",
            "label": "Charts",
            "editable": true,
            "removable": true
          },
          {
            "value": "grid",
            "label": "Grid",
            "disabled": true
          }
        ]
      },
      {
        "value": "docs",
        "label": "Documents",
        "appendable": true,
        "children": [{
          "value": "guide",
          "label": "Guide"
        }]
      }
    ]
  });
</script>

Move nodes

Drag to reorder and inspect the updated nodes in the event.

View code
HTML
<sy-tree
  expandable
  draggable="true"
  expandall
  line
  id="sample"
></sy-tree>

<script type="module">
  const component1 = document.querySelector("#sample");
  Object.assign(component1, {
    "nodes": [{
        "value": "project",
        "label": "Project",
        "expanded": true,
        "appendable": true,
        "children": [{
            "value": "core",
            "label": "Design System",
            "editable": true,
            "removable": true
          },
          {
            "value": "charts",
            "label": "Charts",
            "editable": true,
            "removable": true
          },
          {
            "value": "grid",
            "label": "Grid",
            "disabled": true
          }
        ]
      },
      {
        "value": "docs",
        "label": "Documents",
        "appendable": true,
        "children": [{
          "value": "guide",
          "label": "Guide"
        }]
      }
    ]
  });
</script>

Add and remove from the app

Add or remove nodes using unique keys.

View code
HTML
<sy-tree expandable id="sample"></sy-tree>
<div class="demo-actions"
  style="display:flex;flex-wrap:wrap;gap:8px;margin-top:16px"
>
  <sy-button id="action-0" size="small">Add item to Documents</sy-button>
  <sy-button id="action-1" size="small">Remove added item</sy-button>
</div>
<output id="demo-result" aria-live="polite"></output>

<script type="module">
  const describeResult = value => JSON.stringify(value, (_key, item) => {
    if (item instanceof File) return {
      name: item.name,
      size: item.size,
      type: item.type
    };
    if (item instanceof Element) return `<${item.localName}>`;
    return item;
  }) ?? 'Done';
  const component1 = document.querySelector("#sample");
  Object.assign(component1, {
    "nodes": [{
        "value": "project",
        "label": "Project",
        "expanded": true,
        "appendable": true,
        "children": [{
            "value": "core",
            "label": "Design System",
            "editable": true,
            "removable": true
          },
          {
            "value": "charts",
            "label": "Charts",
            "editable": true,
            "removable": true
          },
          {
            "value": "grid",
            "label": "Grid",
            "disabled": true
          }
        ]
      },
      {
        "value": "docs",
        "label": "Documents",
        "appendable": true,
        "children": [{
          "value": "guide",
          "label": "Guide"
        }]
      }
    ]
  });
  const actionTarget0 = document.querySelector("#sample");
  document.querySelector('#action-0').addEventListener('click', async () => {
    const result = await actionTarget0.manualAddChildNode("docs", "Installation guide",
      "installation");
    document.querySelector('#demo-result').textContent = describeResult(result);
  });
  const actionTarget1 = document.querySelector("#sample");
  document.querySelector('#action-1').addEventListener('click', async () => {
    const result = await actionTarget1.manualRemoveNode("installation");
    document.querySelector('#demo-result').textContent = describeResult(result);
  });
</script>

Events and payloads

Interact with the component and inspect the latest event name and detail. The code includes subscriptions to events emitted by this component and its children.

View code
HTML
<sy-tree
  expandable
  checkable
  clickable
  searchterm=""
  id="sample"
></sy-tree>
<output id="demo-events" aria-live="polite">Interact with the component to see
  its latest event and payload.</output>

<script type="module">
  const describeResult = value => JSON.stringify(value, (_key, item) => {
    if (item instanceof File) return {
      name: item.name,
      size: item.size,
      type: item.type
    };
    if (item instanceof Element) return `<${item.localName}>`;
    return item;
  }) ?? 'Done';
  const component1 = document.querySelector("#sample");
  Object.assign(component1, {
    "nodes": [{
        "value": "project",
        "label": "Project",
        "expanded": true,
        "appendable": true,
        "children": [{
            "value": "core",
            "label": "Design System",
            "editable": true,
            "removable": true
          },
          {
            "value": "charts",
            "label": "Charts",
            "editable": true,
            "removable": true
          },
          {
            "value": "grid",
            "label": "Grid",
            "disabled": true
          }
        ]
      },
      {
        "value": "docs",
        "label": "Documents",
        "appendable": true,
        "children": [{
          "value": "guide",
          "label": "Guide"
        }]
      }
    ]
  });
  for (const name of ["nodesChanged", "itemChecked", "itemSelected", "expandChanged",
      "checkChanged", "itemAdded", "itemRemoved", "itemEdited", "itemUpdating",
      "itemUpdatingReset", "itemDrop", "draggingEvent"
    ]) {
    document.addEventListener(name, event => {
      document.querySelector('#demo-events').textContent =
        `${event.target.localName} · ${name}: ${describeResult(event.detail)}`;
    });
  }
</script>

Set the selected node

Set selectedValue to a node's value to show it as selected. Click an item to inspect its selection event.

View code
HTML
<sy-tree
  expandable
  checkable
  clickable
  searchterm=""
  selectedvalue="core"
  id="sample"
></sy-tree>

<script type="module">
  const component1 = document.querySelector("#sample");
  Object.assign(component1, {
    "nodes": [{
        "value": "project",
        "label": "Project",
        "expanded": true,
        "appendable": true,
        "children": [{
            "value": "core",
            "label": "Design System",
            "editable": true,
            "removable": true
          },
          {
            "value": "charts",
            "label": "Charts",
            "editable": true,
            "removable": true
          },
          {
            "value": "grid",
            "label": "Grid",
            "disabled": true
          }
        ]
      },
      {
        "value": "docs",
        "label": "Documents",
        "appendable": true,
        "children": [{
          "value": "guide",
          "label": "Guide"
        }]
      }
    ]
  });
  const component2 = document.querySelector("#sample");
  Object.assign(component2, {
    "selectedValue": "core",
    "clickable": true
  });
</script>

Approve additions and removals in the app

With manualAdd and manualRemove enabled, the component emits request events and waits for the app. Inspect requests below. In your app, save the changes and update the tree data.

View code
HTML
<sy-tree
  expandable
  checkable
  clickable
  editable
  searchterm=""
  manualadd
  manualremove
  nodewidth="260"
  id="sample"
></sy-tree>

<script type="module">
  const component1 = document.querySelector("#sample");
  Object.assign(component1, {
    "nodes": [{
        "value": "project",
        "label": "Project",
        "expanded": true,
        "appendable": true,
        "children": [{
            "value": "core",
            "label": "Design System",
            "editable": true,
            "removable": true
          },
          {
            "value": "charts",
            "label": "Charts",
            "editable": true,
            "removable": true
          },
          {
            "value": "grid",
            "label": "Grid",
            "disabled": true
          }
        ]
      },
      {
        "value": "docs",
        "label": "Documents",
        "appendable": true,
        "children": [{
          "value": "guide",
          "label": "Guide"
        }]
      }
    ]
  });
  const component2 = document.querySelector("#sample");
  Object.assign(component2, {
    "editable": true,
    "manualAdd": true,
    "manualRemove": true,
    "nodeWidth": 260
  });
</script>

Browse the hierarchy

Expand the hierarchy with guide lines and no selection checkboxes.

View code
HTML
<sy-tree
  expandable
  clickable
  expandall
  line
  searchterm=""
  id="sample"
></sy-tree>

<script type="module">
  const component1 = document.querySelector("#sample");
  Object.assign(component1, {
    "nodes": [{
        "value": "project",
        "label": "Project",
        "expanded": true,
        "appendable": true,
        "children": [{
            "value": "core",
            "label": "Design System",
            "editable": true,
            "removable": true
          },
          {
            "value": "charts",
            "label": "Charts",
            "editable": true,
            "removable": true
          },
          {
            "value": "grid",
            "label": "Grid",
            "disabled": true
          }
        ]
      },
      {
        "value": "docs",
        "label": "Documents",
        "appendable": true,
        "children": [{
          "value": "guide",
          "label": "Guide"
        }]
      }
    ]
  });
  const component2 = document.querySelector("#sample");
  Object.assign(component2, {
    "expandAll": true,
    "line": true,
    "checkable": false,
    "editable": false
  });
</script>

API reference

#

Hover over a name or focus it with the keyboard to see the code. On touch screens, tap the name.

<sy-tree>

Properties

Attribute / PropertyTypeDefaultDescription
TreeNode[][]Array of tree nodes with label, value, and children.

Pass objects and arrays as JavaScript properties.

booleanfalseSelect multiple items using checkboxes.
booleanfalseAllow user selection and emit the selected event.
booleanfalseAllow nodes to be moved by dragging.
booleanfalseAllow node names to be edited.
booleanfalseAllow tree branches to be expanded and collapsed.
booleanfalseExpand all tree branches initially.
booleanfalseHave the app call manualAddChildNode after an add request.
booleanfalseHave the app call manualRemoveNode after a removal request.
booleanfalseShow connectors between parent and child nodes.
number | nullnullDisplay width of tree nodes.
string''Unique key of the selected node.
string''Search query used to filter and highlight candidates.
booleanfalseUsed internally with Tree Select. Keep the default for a regular Select.

Events

EventDetailDescription
CustomEvent<TreeNodesChangedDetail>Read the result from the event's detail.
CustomEvent<TreeItemCheckedDetail>Read the result from the event's detail.
CustomEvent<TreeItemSelectedDetail>Read the result from the event's detail.

Methods

MethodReturnsDescription
Promise<void>Change the checked state of the specified tree node.
Promise<void>Clear all checked tree selections.
Promise<void>Add a new child under a parent node.
Promise<void>Remove a tree node by its unique key.
Promise<TreeNode | null>Find the node matching a unique key in the supplied node array.

<sy-tree-item>

Properties

Attribute / PropertyTypeDefaultDescription
booleanfalseShow the add-child action.
booleanfalseSelect multiple items using checkboxes.
booleanfalseSelected or on state.
booleanfalseAllow user selection and emit the selected event.
booleanfalseBlock user interaction and keyboard focus.
booleanfalseAllow this node to be dragged.
booleanfalseWhether the node is being dragged. Managed by the parent.
'none' | 'valid' | 'invalid''none'Indicate whether dropping is allowed. Managed by the parent.
booleanfalseAllow name editing.
booleanfalseAllow tree branches to be expanded and collapsed.
booleanfalseWhether children are expanded.
booleanfalseRestrict node movement.
booleanfalseIndicate whether child nodes exist.
string'New item'Placeholder for the new node name input.
string''Set icon visibility or icon content. Check the format supported by each component.
booleanfalseIndeterminate state when only some items are selected.
booleanfalseWhether the node is nested under another node. Managed by the parent.
booleanfalseIndicate whether the name is being edited.
string''Label describing the item.
number0Hierarchy depth. Managed by the parent.
booleanfalseAllow the node removal action.
any[][]Child node array, passed down by the parent.

Pass objects and arrays as JavaScript properties.

string''Tag text beside the node.
"gray" | "purple" | "blue" | "green" | "cyan" | "yellow" | "orange" | "red" | undefinedundefinedTag color beside the node.
string''Current value or item identifier.
string''Search query used to filter and highlight candidates.
string''Unique key of the currently selected node.
number | nullnullDisplay width of tree nodes.
booleanfalseShow connectors between parent and child nodes.

Events

EventDetailDescription
CustomEvent<{ value: string; label: string; expanded: boolean }>Read the result from the event's detail.
CustomEvent<{ value: string; label: string; checked: boolean }>Read the result from the event's detail.
CustomEvent<{ parentValue: string; childLabel: string; childValue: string; childLevel: number }>Read the result from the event's detail.
CustomEvent<{ value: string; label: string }>Read the result from the event's detail.
CustomEvent<{ value: string; label: string }>Read the result from the event's detail.
CustomEvent<any>Read the result from the event's detail.
CustomEvent<any>Read the result from the event's detail.
CustomEvent<{ targetKey: string; draggedKey: string; dropPosition: string; targetLevel: number }>Read the result from the event's detail.
CustomEvent<{ value: string; label: string; checked: boolean }>Read the result from the event's detail.
CustomEvent<string>Read the result from the event's detail.

Methods

MethodReturnsDescription
Promise<void>Layout only, and called fire-and-forget by the parent tree, so it never rejects: a no-op before the item started, and it still runs while frozen.