Varendo

TreeNav

Hierarchical navigation with stable node identities, expansion and keyboard semantics.

FamilynavigationLicenseApache-2.0
StandaloneAvailable

Use the web element directly without the semantic runtime.

Semantic bindingAvailable

A registered presentation adapter can bind this component to host-owned meaning and state.

Automatic adaptationNo standard recipe

The standard recipe resolver does not select this component automatically.

Import and live example

A two-level report tree with the reports branch expanded and weekly selected.

Interactive preview requires JavaScript.

View the complete example source
import {registerAeliqoElements} from "@varendo/web";
import {
  AeliqoBreadcrumbElement,
  AeliqoMenuElement,
  AeliqoPaginationElement,
  AeliqoTabsElement,
  AeliqoTreeNavElement,
  type AeliqoBreadcrumbItem,
  type AeliqoMenuItem,
  type AeliqoTabItem,
  type AeliqoTreeNavNode,
} from "@varendo/web/navigation";

const tabs: readonly AeliqoTabItem[] = [
  {id: "overview", label: "Overview", content: "Overview content"},
  {id: "details", label: "Details", content: "Details content"},
  {id: "history", label: "History", content: "History content", disabled: true},
];
const breadcrumb: readonly AeliqoBreadcrumbItem[] = [
  {id: "home", label: "Home", href: "/"},
  {id: "reports", label: "Reports", href: "/reports"},
  {id: "current", label: "Weekly report", current: true},
];
const menuItems: readonly AeliqoMenuItem[] = [
  {id: "open", label: "Open report"},
  {id: "archive", label: "Archive"},
  {id: "disabled", label: "Unavailable", disabled: true},
];
const treeNodes: readonly AeliqoTreeNavNode[] = [
  {id: "reports", label: "Reports", children: [{id: "weekly", label: "Weekly"}, {id: "monthly", label: "Monthly"}]},
  {id: "settings", label: "Settings", disabled: true},
];

registerAeliqoElements();

const host = document.querySelector<HTMLElement>("#aeliqo-example") ?? (() => {
  const created = document.createElement("div");
  created.id = "aeliqo-example";
  (document.body ?? document.documentElement).append(created);
  return created;
})();

function createCatalogRoot(container: HTMLElement): HTMLElement {
  const root = document.createElement("div");
  root.dataset.catalogSourceRoot = "true";
  root.style.display = "grid";
  root.style.gap = "12px";
  container.append(root);
  return root;
}

function createCatalogElement<T extends HTMLElement>(tagName: string, container: HTMLElement): T {
  const element = document.createElement(tagName) as T;
  element.setAttribute("data-aeliqo-theme", "light");
  container.append(element);
  return element;
}

function appendSlottedText(root: HTMLElement, slot: string, textContent: string): void {
  const content = document.createElement("span");
  content.slot = slot;
  content.textContent = textContent;
  root.append(content);
}

const root = createCatalogRoot(host);
(((root) => {
		const element = createCatalogElement<AeliqoTreeNavElement>("aeliqo-tree-nav", root);
		element.nodes = treeNodes;
		element.expandedIds = ["reports"];
		element.selectedId = "weekly";
		element.label = "Report navigation";
	}))(root);

Purpose

A bounded tree of navigation nodes with stable IDs and tree keyboard semantics. It tracks expansion locally and emits selection or expansion requests.

When to use it

When to use a different component

Properties and defaults

Node IDs are stable. After an uncancelled event, the component updates its selected ID or local expanded set; the host can supply selectedId and expandedIds to synchronize external state.

Properties, ownership, and initial values
PropertyUse and ownershipDeclared typeInitial value
nodesSupplies the navigation hierarchy with stable node IDs and bounded children.readonly AeliqoTreeNavNode[][]
expandedIdsSupplies the bounded ordered expanded ids collection used by this component.readonly string[][]
selectedIdControls the currently selected navigation node by stable ID.string''
labelProvides the visible label and accessible name for the component.string'Navigation tree'

Events

Events, payloads, timing, and application responsibilities
EventPayloadEmittedApplication responsibility
aeliqo-tree-nav-selectThe selected enabled node ID.After keyboard or pointer selection.Route or update controlled selectedId.
aeliqo-tree-nav-expandThe node ID and proposed expanded state.After a branch toggle.Update controlled expandedIds while preserving valid selection.

Events cross the component boundary as user proposals. Validate their detail and current authority before applying a business effect.

Listen for aeliqo-tree-nav-select

TypeScript example
const element = document.querySelector('aeliqo-tree-nav');<p>element?.addEventListener('aeliqo-tree-nav-select', (event) => {
  const proposal = (event as CustomEvent<unknown>).detail;
  // Validate the proposal, update host state, then assign controlled properties.
  applyProposal(proposal);
});

Listen for aeliqo-tree-nav-expand

TypeScript example
const element = document.querySelector('aeliqo-tree-nav');</p>
<p>element?.addEventListener('aeliqo-tree-nav-expand', (event) => {
  const proposal = (event as CustomEvent<unknown>).detail;
  // Validate the proposal, update host state, then assign controlled properties.
  applyProposal(proposal);
});

States and failure handling

Relevant states:

Expected result: The tree preserves hierarchy and emits typed selection or expansion requests by node ID.

Node IDs must be unique, nonempty, and at most 160 characters. Cycles, invalid shapes, duplicate IDs, or more than 512 nodes render a status message instead of the tree. expandedIds sets the expansion set; after an uncancelled expand event, the element also updates it locally. An uncancelled selection event updates selectedId. Watch those events to keep routing aligned, and pass new props to reconcile external navigation changes.

Keyboard, focus, and accessibility

Keyboard behavior:

Exposed semantics:

Responsive behavior

Allow long node labels to wrap inside the tree. Keep the selected item and expansion state visible after the host narrows the panel.

Style hooks

Performance limits

Generated TypeScript declaration

View generated declaration
export declare class AeliqoTreeNavElement extends AeliqoFoundationElement {
    static readonly properties: {
        nodes: {
            attribute: boolean;
        };
        expandedIds: {
            attribute: boolean;
        };
        selectedId: {
            type: StringConstructor;
        };
        label: {
            type: StringConstructor;
        };
    };
    static readonly styles: import("lit").CSSResult[];
    nodes: readonly AeliqoTreeNavNode[];
    expandedIds: readonly string[];
    selectedId: string;
    label: string;
    private internalExpanded;
    private focusedId;
    private treeError;
    protected willUpdate(changed: Map<string, unknown>): void;
    private isExpanded;
    private validateNodes;
    private flatVisible;
    private select;
    private toggle;
    private toggleFromPointer;
    private focusNode;
    private keydown;
    private handleArrowRight;
    private handleArrowLeft;
    private focusVisibleIndex;
    private selectFromKeyboard;
    private focusTreeNode;
    private expandedAttribute;
    private renderNode;
    protected render(): import("lit").TemplateResult<1>;
}

Version

This page documents the Varendo 0.6 component contract.