Skip to content

HyDtcgTree

Usage examples on this page are written for Lit / plain HTML (<hy-dtcg-tree>). The same component ships as HyDtcgTree 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 hy-tree specialized for DTCG (W3C Design Tokens Community Group) documents. Pass a parsed DTCG JSON object via tokens, and the wrapper walks it, renders each group as a non-leaf tree item and each token as a leaf item with an inline value preview.

The wrapper owns expansion state (not the underlying hy-tree-items) so filter changes can transparently expand ancestors of matches without fighting the user's manual expansion.

Filter semantics: an item is visible when (1) its own path contains the filter text, (2) any descendant's path does, or (3) an ancestor's path does — in the last case, the ancestor's whole subtree "opens up" (every descendant renders, matching or not). Set strict-filter to disable the third case so only own/descendant matches remain.

Examples

Browser for a DTCG file — value previews follow $type (color swatch, dimension mono, shadow thumb, typography summary, alias chip). Previews show by default; set the valuePreview property to false to hide them.

javascript
<hy-dtcg-tree id="browser"></hy-dtcg-tree>

<script>
const browser = document.getElementById('browser');
browser.tokens = await (await fetch('/tokens.json')).json();
browser.addEventListener('select', (event) => {
console.log(event.detail.path, event.detail.token);
});
</script>

Filterable token picker — non-matching items hide; ancestors of matches stay visible and auto-expand. A matching group "opens up" every descendant regardless of self-match.

javascript
<hy-text-input id="filter" placeholder="Filter tokens" clearable></hy-text-input>
<hy-dtcg-tree id="picker"></hy-dtcg-tree>

<script>
const filter = document.getElementById('filter');
const picker = document.getElementById('picker');
picker.tokens = await (await fetch('/tokens.json')).json();
filter.addEventListener('input', (event) => {
picker.filterText = event.detail.value;
});
</script>

Selection mirrored in the URL — selectedPath is a reflected attribute, so setAttribute and property assignment stay in sync.

html
<hy-dtcg-tree id="router"></hy-dtcg-tree>

<script>
  const tree = document.getElementById('router');
  tree.tokens = await (await fetch('/tokens.json')).json();

  const fromHash = () => tree.setAttribute('selected-path', location.hash.slice(1));
  fromHash();
  window.addEventListener('hashchange', fromHash);

  tree.addEventListener('select', (event) => {
  if (location.hash.slice(1) !== event.detail.path) {
  location.hash = event.detail.path;
  }
  });
</script>

Overriding the clipboard default — the copy event is cancelable and fires before the internal clipboard write

javascript
tree.addEventListener('copy', (event) => {
  event.preventDefault();
  navigator.clipboard.writeText(`{${event.detail.path}}`);
});

Domain-specific key ordering — pass sortKeys to reorder children per parent path (type-scale shorthands, font-weight words, numeric z-index)

javascript
tree.sortKeys = (parentPath, keys) => {
  if (parentPath === 'spacing') {
    const order = ['xs', 'sm', 'md', 'lg', 'xl'];
    return [...keys].sort((a, b) => order.indexOf(a) - order.indexOf(b));
  }
  return keys;
};

API

Properties

PropertyAttributeTypeDefaultDescription
tokensDtcgDocument{}Parsed DTCG document.
selectedPathselected-pathstring''Dot-path of the currently selected token. Reflected.
filterTextfilter-textstring''Case-insensitive substring filter. When non-empty, items whose path or any descendant's path contains the text stay visible; the rest are hidden. Ancestors of matches are auto-expanded.
strictFilterstrict-filterbooleanfalseWhen true, the default "ancestor match opens the whole subtree" semantic is disabled: only items whose own path matches the filter (or that have a descendant that matches) stay visible. Children of a matching ancestor are hidden unless they also match.
copyablecopyablebooleantrueShow the copy-path icon button in each row's trailing slot.
valuePreviewvalue-previewbooleantrueShow inline value previews (swatch, dimension, shadow thumb, etc.).
showTypeBadgeshow-type-badgebooleanfalseRender a compact 3-letter badge of the token's $type in the row's leading slot (opt-in). Disabled by default to keep the tree minimal. Colors come from typeColor(type) when set, otherwise fall back to the shared --hy-dtcg-tree-type-badge-* custom properties (see styles).
showGroupMetashow-group-metabooleanfalseRender a compact child-count and inherited $type label in the trailing slot of each group row (opt-in). Good for token browsers where "how many children" and "what type does this group contain" are useful at-a-glance facts.
sizesize'small' | 'medium' | 'large''medium'Size forwarded to the internal hy-tree (and through to every hy-tree-item). small produces the dense rows typical of token browsers; medium is the default.
expandOnexpand-on'chevron' | 'row' | 'double-click''row'Activation policy for row clicks — forwarded to the inner hy-tree. Defaults to 'row' (not 'chevron', the underlying tree's default) because token browsers have no "select a group without expanding it" use case: every group exists to be opened. See the expand-on matrix on hy-tree for the full behavior.
emptyTextempty-textstring'No tokens match'Text shown in the empty state when the filter excludes everything.
sortKeysSortKeysFnidentitySortHook for domain-specific key ordering. Called with a parentPath (empty string at the root) and the list of child keys at that path. Return a reordered list. Default is identity (preserves source ordering from Object.keys).
typeColorTypeColorFn | undefinedOptional per-type color override for the type badge. Return null or undefined to fall back to the CSS custom-property defaults. Consumers with a pre-existing color map can pass it directly:
decorateRowRowDecorationFn | undefinedOptional per-row badge decorator. Called once per rendered row; the returned { badge, variant } is rendered in the row's leading slot (after the type badge, if any). Return null / undefined to skip.
rowActionsRowActionsFn | undefinedOptional per-row context-menu builder. When set, right-clicking a row calls this function with { path, isToken, token }; if it returns a non-empty MenuAction[], the wrapper opens an internal hy-context-menu at the pointer and fires action with { path, action, isToken, token } when the user picks an item.

Events

EventDetailDescription
select{ path, token } — fires when the user clicks a tree item.
copy{ path } — cancelable; fires before the internal clipboard write. Call preventDefault() to suppress the default write and own it.
action{ path, action, isToken, token } — fires when the user picks an item from the per-row context menu (when rowActions is set).

Slots

SlotDescription
headerForwarded to the inner hy-tree's header slot.
emptyShown when the filter excludes every item.

CSS Parts

PartDescription
emptyContainer for the empty-state message (shown when the filter excludes every item).

Methods

expandAll()

Expose the internal tree's imperative methods for advanced use.

resetExpansion()

Clear all expansion state. Useful when the consumer knows the document content changed meaningfully without a reference-swap.

Built with Lit. Documented with VitePress.