HyDtcgTree
Usage examples on this page are written for Lit / plain HTML (
<hy-dtcg-tree>). The same component ships asHyDtcgTreein@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.
<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.
<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.
<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
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)
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
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
tokens | — | DtcgDocument | {} | Parsed DTCG document. |
selectedPath | selected-path | string | '' | Dot-path of the currently selected token. Reflected. |
filterText | filter-text | string | '' | 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. |
strictFilter | strict-filter | boolean | false | When 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. |
copyable | copyable | boolean | true | Show the copy-path icon button in each row's trailing slot. |
valuePreview | value-preview | boolean | true | Show inline value previews (swatch, dimension, shadow thumb, etc.). |
showTypeBadge | show-type-badge | boolean | false | Render 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). |
showGroupMeta | show-group-meta | boolean | false | Render 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. |
size | size | '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. |
expandOn | expand-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. |
emptyText | empty-text | string | 'No tokens match' | Text shown in the empty state when the filter excludes everything. |
sortKeys | — | SortKeysFn | identitySort | Hook 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). |
typeColor | — | TypeColorFn | undefined | — | Optional 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: |
decorateRow | — | RowDecorationFn | undefined | — | Optional 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. |
rowActions | — | RowActionsFn | undefined | — | Optional 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
| Event | Detail | Description |
|---|---|---|
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
| Slot | Description |
|---|---|
header | Forwarded to the inner hy-tree's header slot. |
empty | Shown when the filter excludes every item. |
CSS Parts
| Part | Description |
|---|---|
empty | Container 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.