Tree
Hierarchical tree view with expansion, selection, checkboxes and lazy loading.
c2-tree
Hierarchical tree view with expansion, selection and lazy loading.
It can be authored two ways, and both produce the same DOM and the same events. Nest the rows in markup:
<c2-tree expanded-items="src">
<c2-tree-item value="src" label="src">
<c2-tree-item value="app.ts" label="app.ts"></c2-tree-item>
</c2-tree-item>
</c2-tree>
…or hand it data, which it renders into the same c2-tree-item elements:
tree.items = [{ value: 'src', label: 'src', children: [{ value: 'app.ts', label: 'app.ts' }] }]
The tree owns all state. value holds the selected rows, expanded-items the expanded ones, and every
row's expanded, selected, indeterminate, level and roving tabindex are written from here on each
sync — so drive those two arrays rather than the rows.
In the data-driven mode renderItem takes over a row's whole content, or renderIcon, renderLabel and
renderActions replace one part each. They are handed to Lit, so they return a Lit template or a DOM node —
not framework markup such as JSX.
children-outline draws a vertical rule per level of depth, the way a file explorer marks which branch each
row belongs to. It is off by default; --c2-tree-item__guide--color and --c2-tree-item__guide--width style
the rules once it is on.
Only expanded rows render their children slot, which keeps a collapsed subtree out of both layout and the accessibility tree — though the child elements are still created. Reach for virtualization rather than this component once a tree runs to many thousands of rows.
Keyboard
Arrow Up and Down walk the visible rows. Arrow Right expands a collapsed branch, then moves to its first
child; Arrow Left collapses an expanded one, then moves to its parent. Home and End jump to the ends, Enter
and Space select, * expands every sibling of the focused row, and typing a few letters jumps to the
matching row. With selection="multiple", Shift extends a range and Ctrl or Cmd toggles a single row.
Attributes
| Name | Type | Default | Description |
|---|---|---|---|
items | TreeNode[] | [] | Nodes to render. Leave empty and nest c2-tree-item elements instead to author the tree in markup. |
value | string[] | [] | Values of the selected rows. Reflected as a ;-separated attribute. |
expanded-items | string[] | [] | Values of the expanded rows. Reflected as a ;-separated attribute. |
selection | TreeSelectionMode | single | How many rows may be selected at once. |
checkbox-selection | boolean | false | Shows a checkbox on every row. Implies selection="multiple". |
selection-propagation | TreeSelectionPropagation | both | How a checkbox tick travels between a row and its relatives. |
children-outline | boolean | false | Draws a vertical rule per level of depth, marking which branch each row belongs to. |
disabled | boolean | false | Freezes the whole tree. |
expand-on-click | boolean | false | Expands a branch when its row is clicked — or activated with Enter or Space — not only when its toggle is. |
Slots
| Name | Description |
|---|---|
(default) | The root c2-tree-item rows, when authoring in markup. |
empty | Shown instead of the rows when the tree holds nothing. |
Events
| Name | Type | Description |
|---|---|---|
expansion-change | CustomEvent<TreeExpansionChangeEventDetail> | Fired after a row is expanded or collapsed. Does not bubble. |
item-load-error | CustomEvent<TreeItemLoadErrorEventDetail> | Fired when loadChildren rejects. |
selection-change | CustomEvent<TreeSelectionChangeEventDetail> | Fired after the user changes the selection. Does not bubble: several components fire selection-change, so a listener belongs on the element itself. |
item-click | CustomEvent<TreeItemClickEventDetail> | Fired when a row is clicked, selected or not. |
item-expand | CustomEvent<TreeItemExpandEventDetail> | Fired when a row expands. Call preventDefault() to keep it closed. This is where a consumer authoring in markup appends children for a lazily loaded branch. |
CSS parts
Shadow DOM styling hooks used with ::part(name). Prefer CSS custom properties when they cover the change.
| Name | Description |
|---|---|
tree | The scrolling container holding the rows. |
CSS custom properties
Grouped by semantic target and state from --c2-component__target__state--property. Click a group to collapse it; click a name to copy it.
| Name | Type | Default | Description |
|---|---|---|---|
--c2-tree--background | color | #ffffff | Background of the tree. |
--c2-tree--padding-top | padding | 4px | Space above the first row. |
--c2-tree--padding-right | padding | 0px | Space right of the rows. |
--c2-tree--padding-bottom | padding | 4px | Space below the last row. |
--c2-tree--padding-left | padding | 0px | Space left of the rows. |
--c2-tree--border-top | border | — | Top border. |
--c2-tree--border-right | border | — | Right border. |
--c2-tree--border-bottom | border | — | Bottom border. |
--c2-tree--border-left | border | — | Left border. |
--c2-tree--border-top-left-radius | border-radius | 8px | Top-left corner radius. |
--c2-tree--border-top-right-radius | border-radius | 8px | Top-right corner radius. |
--c2-tree--border-bottom-left-radius | border-radius | 8px | Bottom-left corner radius. |
--c2-tree--border-bottom-right-radius | border-radius | 8px | Bottom-right corner radius. |
--c2-tree--max-height | pixel | — | Height at which the tree starts scrolling. |
--c2-tree--font-size | font-size | 14px | Base font size, inherited by the rows. |
--c2-tree--font-family | font-family | — | Base font family, inherited by the rows. |
--c2-tree__disabled--opacity | opacity | 0.38 | Opacity of a disabled tree. |
--c2-tree__empty--color | color | #71717a | Colour of the empty message. |
--c2-tree__empty--padding | padding | 18px | Space around the empty message. |
c2-tree-item
One row of a https://github.com/code2nguyen/web-components | c2-tree.
Nest items to build the hierarchy — a branch's children are its own c2-tree-item element children:
<c2-tree>
<c2-tree-item value="src" label="src">
<c2-tree-item value="app.ts" label="app.ts"></c2-tree-item>
</c2-tree-item>
</c2-tree>
The item draws a row and nothing else: expanded, selected, indeterminate, level and the roving
tabindex are all written by the parent c2-tree, which owns the tree's state. Setting them by hand works
but is overwritten on the tree's next sync — drive the tree's value and expanded-items instead.
The children slot is only rendered while the row is expanded, so a collapsed subtree is not laid out and stays out of the accessibility tree. The child elements themselves still exist in the DOM.
Attributes
| Name | Type | Default | Description |
|---|---|---|---|
value | string | — | Identity of the row. Selection and expansion are tracked by this value, so it must be unique in the tree. |
label | string | — | Text of the row. Ignored when the label slot is filled; falls back to value when empty. |
disabled | boolean | false | Blocks selection and expansion, and takes the row out of checkbox propagation. |
has-children | boolean | false | Marks a branch whose children load on demand: the toggle shows before any child exists. |
href | string | — | Turns the row into a link. The whole row becomes the click target; the toggle still only expands. |
target | string | undefined | — | Browsing context for href, e.g. _blank. A _blank row gets rel="noopener noreferrer". |
expanded | boolean | false | Whether the children are shown. Written by the parent c2-tree. |
selected | boolean | false | Whether the row is selected. Written by the parent c2-tree. |
indeterminate | boolean | false | Whether only part of the subtree is selected. Derived and written by the parent c2-tree. |
loading | boolean | false | Whether the children are being fetched. Written by the parent c2-tree. |
children-outline | boolean | false | Whether to draw the indent guides. Written by the parent c2-tree, and reflected because the rules are
drawn in CSS and the stylesheet has to see it. |
Slots
| Name | Description |
|---|---|
(default) | The nested c2-tree-item children of this row. |
label | Rich label content, replacing the label attribute. |
icon | Icon shown between the disclosure toggle and the label. |
actions | Trailing content, revealed on hover and focus by default. |
toggle-icon | Replaces the default chevron. It is rotated by the component, so supply the collapsed orientation. |
CSS parts
Shadow DOM styling hooks used with ::part(name). Prefer CSS custom properties when they cover the change.
| Name | Description |
|---|---|
row | The clickable row, excluding any nested children. |
toggle | The disclosure toggle. |
label | Text box containing the label slot or label-property fallback. |
actions | Trailing box wrapping the assigned actions slot. |
group | The container holding the nested children. |
checkbox | The selection checkbox rendered when checkbox selection is enabled. |
CSS custom properties
Grouped by semantic target and state from --c2-component__target__state--property. Click a group to collapse it; click a name to copy it.
| Name | Type | Default | Description |
|---|---|---|---|
--c2-tree-item--color | color | #18181b | Label colour. |
--c2-tree-item--background | color | transparent | Row background at rest. |
--c2-tree-item--font-size | font-size | 14px | Label size. |
--c2-tree-item--font-weight | font-weight | — | Label weight. |
--c2-tree-item--font-family | font-family | — | Label family. |
--c2-tree-item--line-height | pixel | 20px | Label line height. |
--c2-tree-item__row--min-height | pixel | 28px | Height of a row. |
--c2-tree-item__row--indent | pixel | 16px | Extra inset added per level of depth. |
--c2-tree-item__row--padding-top | padding | 0px | Space above the row's content. row--min-height is a floor, so this only grows the row once content plus padding passes it. |
--c2-tree-item__row--padding-bottom | padding | 0px | Space below the row's content. See row--padding-top for how it interacts with row--min-height. |
--c2-tree-item__row--padding-inline-start | padding | 8px | Inset of a root-level row. |
--c2-tree-item__row--padding-inline-end | padding | 8px | Space after the trailing actions. |
--c2-tree-item__row--gap | pixel | 6px | Space between toggle, checkbox, icon, label and actions. |
--c2-tree-item__row--border-radius | border-radius | 4px | Corner radius of the row highlight. Set 0 for edge-to-edge bands. |
--c2-tree-item__hover--color | color | — | Label colour while hovered. Defaults to the resting colour. |
--c2-tree-item__hover--background | color | #f4f4f5 | Row background while hovered. |
--c2-tree-item__selected--color | color | rgb(2, 101, 220) | Label colour while selected. |
--c2-tree-item__selected--background | color | #edf1fe | Row background while selected. |
--c2-tree-item__selected__hover--background | color | #e2e9fd | Row background while selected and hovered. |
--c2-tree-item__focus--outline | outline | 2px solid rgba(2, 101, 220, 0.4) | Focus ring. |
--c2-tree-item__focus--outline-offset | pixel | -2px | Focus ring inset. |
--c2-tree-item__disabled--opacity | opacity | 0.38 | Opacity of a disabled row. |
--c2-tree-item__toggle--size | pixel | 16px | Size of the disclosure toggle. |
--c2-tree-item__toggle--color | color | #71717a | Colour of the disclosure toggle. |
--c2-tree-item__toggle--rotate | angle | 90deg | Toggle rotation while expanded. |
--c2-tree-item__toggle--rotate-collapsed | angle | 0deg | Toggle rotation while collapsed. |
--c2-tree-item__toggle--transition-duration | time | 150ms | Length of the toggle rotation. |
--c2-tree-item__icon--size | pixel | 16px | Size of slotted icons. |
--c2-tree-item__icon--color | color | — | Colour of slotted icons. |
--c2-tree-item__guide--color | color | #e4e4e7 | Colour of the indent guides. |
--c2-tree-item__guide--width | pixel | 1px | Thickness of the indent guides. |
--c2-tree-item__actions--gap | pixel | 2px | Space between trailing actions. |
--c2-tree-item__actions--opacity | opacity | 0 | Opacity of the trailing actions at rest. Set 1 to always show them. |
--c2-tree-item__actions__hover--opacity | opacity | 1 | Opacity of the trailing actions while the row is hovered or focused. |
--c2-tree-item__checkbox--margin-inline-end | pixel | 2px | Space after the selection checkbox. |