Skip to content

HyTreeItem

Usage examples on this page are written for Lit / plain HTML (<hy-tree-item>). The same component ships as HyTreeItem in @whitespaceux/harmony-react (native React 19), with typed wrappers for Angular, Solid, Svelte, and Vue. The API reference below applies to all frameworks.

A single row inside an hy-tree. Renders a chevron, an optional leading icon slot, the label (or default slot), an optional trailing slot, and a hidden-by-default children slot that unhides when expanded is true.

Items are focus-managed by the parent tree via roving tabindex — call setTabIndex(0) to mark the item as the tab target, and focus() to move keyboard focus. The host element carries role="treeitem" and reflects aria-expanded, aria-selected, aria-disabled.

Click zones depend on the parent tree's expand-on policy (forwarded onto each item). The chevron always toggles expansion and stops propagation. The row's click does one of three things, layered:

  1. Non-selectable rows with children always expand on row click — their row has no rival action, so the chevron-only fallback would leave the row dead.
  2. With expand-on='row' (and the row is selectable + has children), the row click both selects AND expands.
  3. Otherwise ('chevron' default, or 'double-click'), the row click just selects; expansion goes through the chevron or dblclick.

Level, aria-level, aria-posinset, and aria-setsize are written by the parent hy-tree during its DOM walk — don't set them manually on an item. The item detects whether it has children by observing its own children slot; it does not read across the DOM.

Examples

Nested file-explorer rows

html
<hy-tree>
  <hy-tree-item value="src" label="src" expanded>
    <hy-tree-item slot="children" value="src/index.ts" label="index.ts"></hy-tree-item>
    <hy-tree-item slot="children" value="src/app.ts" label="app.ts"></hy-tree-item>
  </hy-tree-item>
  <hy-tree-item value="package.json" label="package.json"></hy-tree-item>
  <hy-tree-item value="readme" label="README.md"></hy-tree-item>
</hy-tree>

Leading icon and trailing content

html
<hy-tree-item value="tokens" label="tokens.json" selected>
  <hy-icon slot="leading" name="folder" decorative></hy-icon>
  <span slot="trailing">12 kB</span>
</hy-tree-item>

API

Properties

PropertyAttributeTypeDefaultDescription
valuevaluestring''Identifier used in tree-item-click / expand / collapse events.
labellabelstring''Label text. When empty, the default slot is rendered.
expandedexpandedbooleanfalseWhether the children group is visible. Reflected.
selectedselectedbooleanfalseWhether this item is the selected one in its tree. Reflected.
activeactivebooleanfalseWhether this item currently owns the tab stop in its tree's roving tabindex (i.e. the parent tree's keyboard focus rests here). Reflected so the modal focus trap can match hy-tree-item[active] and so consumer CSS can highlight the current item independent of selection. Managed by the parent hy-tree — do not set manually.
disableddisabledbooleanfalseDisables the item — skipped in keyboard nav, no click activation.
selectableselectablebooleantrueWhen false, clicking the row focuses the item but does not produce a selection. Use on group-only rows (e.g. category headers in a DTCG tree).
levellevelnumber0Nesting depth — written by the parent hy-tree during its walk. Do not set manually.
sizesize'small' | 'medium' | 'large''medium'Size variant. Inherited from the parent hy-tree when there is one, else from the parent hy-tree-item — set it on the root and every nested item follows. An explicit value on a nested item is overwritten by its parent's, exactly as hy-tree has always overwritten every item's: one size per tree, set at the top.
expandOnexpand-on'chevron' | 'row' | 'double-click''chevron'Activation policy for the row's primary click. Inherited from the parent hy-tree when there is one, else from the parent hy-tree-item — set it on the root, not on every row. A nested item's own value is overwritten by its parent's.
hasChildrenbooleanWhether this item has slotted children (auto-detected via slotchange).

Events

EventDetailDescription
tree-item-click{ value, item, originalEvent } — bubbles to parent tree.
expand{ value, item } — bubbles to parent tree.
collapse{ value, item } — bubbles to parent tree.
tree-structure-changeInternal structural notification to the ancestor tree (children added/removed, so it can re-stamp spatial attributes). Bubbles but does not cross shadow DOM (composed: false).

Slots

SlotDescription
defaultLabel content when the label prop is empty.
leadingLeading icon or avatar.
trailingTrailing content (value preview, copy button, badge).
childrenNested hy-tree-item elements.
expand-iconOverride the default chevron icon.

CSS Parts

PartDescription
rowThe interactive row element.
chevronThe chevron region.
labelThe label container.
childrenThe nested-children container.

CSS Custom Properties

PropertyDescription
--hy-tree-item-background-rest
--hy-tree-item-background-hover
--hy-tree-item-background-selected
--hy-tree-item-foreground-default
--hy-tree-item-foreground-subtle
--hy-tree-item-foreground-disabled
--hy-tree-item-gap
--hy-tree-item-padding-block
--hy-tree-item-padding-inline
--hy-tree-item-radius
--hy-tree-item-indent
--hy-tree-item-chevron-size
--hy-tree-item-expand-durationTransition duration for the expand and collapse animation
--hy-tree-item-expand-easingTransition easing for the expand and collapse animation

Methods

setTabIndex()

Sets tabindex on the focusable row element AND mirrors the tab-stop state to the host's reflected [active] attribute so the focus trap (and CSS) can see which item is the current tab stop. Called by the parent tree's roving-tabindex controller.

focus()

Imperative focus — delegates to the row element.

toggleExpand()

Toggle expansion. No-op if the item has no children or is disabled.

Built with Lit. Documented with VitePress.