Skip to main content
Neural UIv2.0.0Documentation
View v1 GitHub

TreeTable

Display hierarchical records in columns, with explicit relationships, expansion and selection.

Category
Data and hierarchy
Import
@neural-ui/core/tree-table
Selector
neu-tree-table
import { NeuTreeTableComponent } from '@neural-ui/core/tree-table';

Hierarchy and expansion

Use TreeTable when hierarchical records also need columns, such as a work breakdown with task names and hours. It is an independent component: Tree shows hierarchy without columns; Table shows flat records.

Supply records in data and relationships in hierarchy. rowKey identifies each record; roots and child relations refer to those keys. A loaded empty child relation means a leaf, while unloaded means children have not been fetched. Apply expandedKeysChange.next to accept expansion or collapse.

Hierarchy and expansion
Task Hours
Delivery
12

Expanded keys: โ€”

Configurator

Change density, borders, stripes, sticky headings, indentation and selection mode. Expansion and selection remain interactive; the generated template reflects the applied settings.

Configurator
Task Hours
Design
24
Research
8
Prototype
16
Delivery
12

The generated template reflects the selected options. The Code tab includes data, imports and state.

template.html
<neu-tree-table
  [data]="rows()"
  [columns]="columns()"
  [rowKey]="rowKey"
  [hierarchy]="hierarchy"
  [labels]="labels()"
  [appearance]='{
      "density": "normal",
      "borders": "rows",
      "striped": false,
      "stickyHeader": false,
      "responsive": "contained-scroll"
    }'
  [hierarchyOptions]='{
      "treeColumnId": "name",
      "indentSize": 20
    }'
  [expandedKeys]="expanded()"
  (expandedKeysChange)="expanded.set($event.next)"
  [selection]="selection()"
  [selectionOptions]='{
      "mode": "single",
      "indicator": "radio",
      "selectOnRowClick": true,
      "allowClear": false
    }'
  (selectionChange)="selection.set($event.next)"
  [query]="query()"
  (queryChange)="query.set($event)"
  [filterOptions]='{
      "surfaces": [],
      "globalFields": [],
      "predicates": {},
      "debounceMs": 0,
      "commit": "immediate"
    }'
  [exportOptions]="{ formats: ['csv'], defaultFilename: 'work-plan' }"
/>

Select loaded descendants

The example uses checkbox selection with loaded-subtree propagation. Selecting Design also selects its loaded children. selectionChange proposes next; the application applies it to selection.

Propagation is limited to loaded relationships. It does not select unknown descendants on the server. Choose propagation none when each node should be selected independently.

Select loaded descendants
Task Hours
Design
24
Research
8
Prototype
16
Delivery
12

Selected keys: โ€”

Load roots and children

In remote mode, dataRequest distinguishes roots from children requests. A children request includes parentKey; both carry query, hierarchy and relation revisions plus a requestId. Your application loads records and applies the matching relationship.

This is a local simulation with an explicit response button, not a network service. Apply the roots, expand Design, then apply its children. In production, preserve request identity and reject stale responses. A relation's loading, error and loaded states belong to application state.

Load roots and children

Apply the roots response first. Then expand Design and apply its children response.

Task Hours
No tasks

Pending request: โ€”

Virtualize visible rows

Virtualization renders a window of visible hierarchical rows. Supply fixed itemSize and overscan values and keep row content within that height. Expansion changes the flattened visible sequence; it does not require replacing the hierarchy with Table data.

When virtualization is enabled, contained scrolling takes precedence over stacked responsive rows to preserve fixed-height geometry. rangeChange reports the window; remote hierarchy loading remains a separate roots/children contract.

Virtualize visible rows
Task Hours
Task 1
1
Task 2
2
Task 3
3
Task 4
4
Task 5
5
Task 6
6
Task 7
7
Task 8
8
Task 9
1
Task 10
2
Task 11
3
Task 12
4
Task 13
5
Task 14
6

Accessibility and keyboard

Core supplies treegrid structure, hierarchy levels, expansion state and keyboard navigation. Your application supplies a meaningful table name, understandable headings and names for custom controls. A custom node template must retain the purpose and readable name of its node.

Use the tree column for hierarchy and keep focus visible when expanding, selecting or editing. Test loaded-subtree selection, remote error/retry paths and custom editors with your real content and assistive technology.

Key
Action
Tab / Shift+Tab Enter and leave the treegrid and its enabled controls.
ArrowUp / ArrowDown Move through visible rows when row navigation is enabled.
ArrowRight / ArrowLeft Expand or collapse a node in hierarchical navigation.
Enter / Space Activate the focused expansion or selection control.

API

TreeTable has its own public types and template contexts. Do not substitute Table options or events just because names resemble each other. Inputs hold applied state; proposal outputs ask your application to apply next state. There are no two-way models on TreeTable.

Inputs

Configure the component with [property]="value". Your application supplies these values; the component does not replace the state you pass in.

Name
Type
Default
Template binding
Description
appearanceNeuTreeTableAppearance{ density: 'normal', borders: 'rows', striped: false, stickyHeader: false, responsive: 'contained-scroll', }[appearance]Density, border mode, stripes, sticky headings and responsive presentation.
columnsreadonly NeuTreeTableColumn<T, F>[][][columns]TreeTable column ids, headings, fields and optional feature descriptors.
datareadonly T[][][data]Loaded node records; hierarchy references them by rowKey.
dataModeNeuTreeTableDataMode'client'[dataMode]client uses loaded relationships; remote emits requests for roots and children.
editingOptionsNeuTreeTableEditingOptions<T, K, F>{ mode: 'none' }[editingOptions]None, cell or row editing and an optional validator returning true or an error message.
editStateNeuTreeTableEditState<K>{ kind: 'none', }[editState]Applied active node cell or row editing session, or kind none.
expandedKeysreadonly K[][][expandedKeys]Applied keys of expanded nodes.
exportOptionsNeuTreeTableExportOptions{ formats: [], defaultFilename: 'tree-table', }[exportOptions]Enabled export formats and the default file name.
filterOptionsNeuTreeTableFilterOptions<T, F>{ surfaces: [], globalFields: [], predicates: {}, debounceMs: 0, commit: 'immediate' }[filterOptions]Filter surfaces, global fields, predicates, debounce and immediate or explicit commit.
hierarchyNeuTreeTableHierarchy<K>EMPTY_HIERARCHY as NeuTreeTableHierarchy<K>Derived default[hierarchy]Roots and child relations, with loaded/loading/error/unloaded state and revision identities.
hierarchyOptionsNeuTreeTableHierarchyOptionsRequired[hierarchyOptions]Column used for the tree and indentation in pixels per depth level.
interactionOptionsNeuTreeTableInteractionOptions{ navigation: 'row', wrapFocus: false, announceChanges: false, contextMenuAction: false, }[interactionOptions]Row keyboard navigation, focus wrapping, announcements and context-menu action.
labelsNeuTreeTableLabels{ ariaLabel: 'Tree table', empty: 'No data', loading: 'Loading', error: 'Unable to load tree data', retry: 'Retry', expand: 'Expand node', collapse: 'Collapse node', selection: 'Selection', pagination: 'Pagination', }[labels]Localized treegrid name, expansion, selection, pagination and state messages.
layoutNeuTreeTableLayoutState{ order: [], hidden: [], widths: {}, pinnedStart: [], pinnedEnd: [], }[layout]Applied column order, visibility, widths and pinning.
paginationOptionsNeuTreeTablePaginationOptions{ enabled: false, pageSizeOptions: [], position: 'bottom', report: 'none', }[paginationOptions]TreeTable pagination policy and root-page controls.
queryNeuTreeTableQuery<F>{ page: 0, pageSize: 25, search: '', sort: [], filters: null, }[query]Applied page, size, search, sort and filter expression using TreeTable types.
rowKey(value: T) => KRequired[rowKey]Required stable unique key function for a node record.
rowOptionsNeuTreeTableRowOptions<T>{}[rowOptions]Optional className function returning application CSS classes for a node row.
selectionNeuTreeTableSelection<K>{ kind: 'keys', keys: [], }[selection]Applied selected node keys. Selection does not modify hierarchy or data.
selectionOptionsNeuTreeTableSelectionOptions<T>{ mode: 'none' }[selectionOptions]Mode, indicators, row-click selection, modifiers, ranges and loaded-subtree propagation.
sortOptionsNeuTreeTableSortOptions{ mode: 'single', removable: true, defaultDirection: 'asc', resetRootPageOnChange: true, }[sortOptions]Single or multiple sorting, initial direction, removal and root-page reset behavior.
virtualizationOptionsNeuTreeTableVirtualizationOptions{ enabled: false }[virtualizationOptions]Enable a fixed-height visible-row window with itemSize and overscan.

Outputs

Listen to an event with (event)="handler($event)". The table explains the data your handler receives and how to use it.

Name
Payload
Template binding
Description
dataRequestNeuTreeTableDataRequest<K, F>(dataRequest)="onDataRequest($event)"Requests roots or children with query/hierarchy/relation revisions and request id; children include parentKey.
editCancelNeuTreeTableEditCancel<T, K>(editCancel)="onEditCancel($event)"Reports cancellation of node editing without committing the draft.
editCommitNeuTreeTableEditCommit<T, K, F>(editCommit)="onEditCommit($event)"Proposes a node draft with its key, field, original value and source; apply accepted changes to data.
editStateChangeNeuTreeTableEditChange<K>(editStateChange)="onEditStateChange($event)"Proposes the next editing session through next.
expandedKeysChangeNeuTreeTableExpandedKeysChange<K>(expandedKeysChange)="onExpandedKeysChange($event)"Proposes next expanded keys, changedKey and toggle/keyboard source.
exportRequestNeuTreeTableExportRequest<F>(exportRequest)="onExportRequest($event)"Requests an application-managed hierarchical export.
featureErrorNeuTreeTableFeatureError(featureError)="onFeatureError($event)"Reports a typed hierarchy or feature diagnostic.
layoutChangeNeuTreeTableLayoutChange(layoutChange)="onLayoutChange($event)"Proposes a column layout update; the application owns the applied layout.
queryChangeNeuTreeTableQuery<F>(queryChange)="onQueryChange($event)"Proposes the complete next TreeTable query; apply $event to query.
rangeChangeNeuTreeTableRangeChange(rangeChange)="onRangeChange($event)"Reports the visible/rendered hierarchical row window.
rowActionNeuTreeTableRowAction<T, K>(rowAction)="onRowAction($event)"Reports a node row interaction with its node identity.
selectionChangeNeuTreeTableSelectionChange<T, K>(selectionChange)="onSelectionChange($event)"Proposes next selection with added/removed keys, loaded values and propagation policy.

Templates

ng-content projects content into the component. TemplateRef inputs receive a template; ng-template directives identify templates with a typed context. A directive shared by an entrypoint is not necessarily a slot of this component.

Name
Mechanism
Contract
NeuTreeTableCaptionDirective

Above the table

Public template directive (entrypoint)

A heading identifies this data set.

ng-template[neuTreeTableCaption]

Context used: โ€”

NeuTreeTableCellDirective

Body cell

Public template directive (entrypoint)

Customer names or planned hours use your own presentation.

ng-template[neuTreeTableCell]

Context used: $implicit

NeuTreeTableEditorDirective

Active cell editor

Public template directive (entrypoint)

Click an editable cell, change its value, then save or cancel.

ng-template[neuTreeTableEditor]

Context used: draftValue, update, commit, cancel

NeuTreeTableEmptyDirective

Empty data area

Public template directive (entrypoint)

Choose Empty in the example to see this message.

ng-template[neuTreeTableEmpty]

Context used: โ€”

NeuTreeTableErrorDirective

Failed data area

Public template directive (entrypoint)

Choose Error, then use Retry to request the data again.

ng-template[neuTreeTableError]

Context used: retry

NeuTreeTableFooterDirective

Column footer

Public template directive (entrypoint)

A label appears below the data in the specified column.

ng-template[neuTreeTableFooter]

Context used: โ€”

NeuTreeTableHeaderDirective

Column heading

Public template directive (entrypoint)

The heading uses the column label with custom markup.

ng-template[neuTreeTableHeader]

Context used: column

NeuTreeTableLoadingDirective

Loading data area

Public template directive (entrypoint)

Choose Loading to display a status message.

ng-template[neuTreeTableLoading]

Context used: โ€”

NeuTreeTableNodeDirective

Hierarchy column

Public template directive (entrypoint)

Expand Design to see child tasks and their depth.

ng-template[neuTreeTableNode]

Context used: $implicit, depth

NeuTreeTableSummaryDirective

Below the table

Public template directive (entrypoint)

An application-owned total accompanies the table.

ng-template[neuTreeTableSummary]

Context used: โ€”

NeuTreeTableToolbarDirective

Before the rows

Public template directive (entrypoint)

Instructions or application actions accompany the data.

ng-template[neuTreeTableToolbar]

Context used: โ€”

Usage example

Import TreeTable directives, not Table directives. neuTreeTableNode customizes the hierarchy column content; neuTreeTableCell customizes a specific column. The context includes the node, depth and state. Its editor uses draftValue and update, not Table's editor contract. Use the state selector to inspect empty, loading and error content.

Customize content

Use the pencil to edit the hours. Save the change or cancel from the editor.

Work plan
Task Hours
Design(level 0)
24 h
Research(level 1)
8 h
Prototype(level 1)
16 h
Delivery(level 0)
12 h
Planned hours

Available tasks: 4

Public methods

Name
Contract
exportexport(request: NeuTreeTableExportRequest<F>): Promise<NeuTreeTableExportOutcome>;

Export visible, loaded, or selected data. Check the returned outcome and handle delegated requests in your application.

example.ts
await table()?.export({ format: 'csv', scope: 'visible' });
focusfocus(target: NeuTreeTableFocusTarget<K>): void;

Focus a node, a cell, or the first or last visible node. This does not expand collapsed parents.

example.ts
table()?.focus({ kind: 'node', key: 'design' });
retryDataretryData(target: NeuTreeTableRetryTarget<K>): void;

Retry loading roots or the children of one parent. The application handles the resulting dataRequest.

example.ts
table()?.retryData({ kind: 'children', parentKey: 'design' });
scrollToscrollTo(target: NeuTreeTableScrollTarget<K>): void;

Scroll to a node, row index, or pixel offset. Choose the target kind explicitly.

example.ts
table()?.scrollTo({ kind: 'node', key: 'design' });

Public Types

Open a type to inspect its definition and interface fields.

Appearance and tokens

Use appearance to choose density, borders, stripes and sticky headings. These options change TreeTable's own renderer. Keep responsive contained-scroll for wide data or use stacked for short non-virtual layouts.

The local example overrides TreeTable cell block/inline padding and selection background. Shared surface, text and focus tokens also affect other components inside the wrapper. Select a density and border mode to compare their actual effect; use the selection example above to understand selected rows.

Specific tokens

Token
Purpose
State / variant
Default / source
Fallback
--neu-tree-table-cell-block Base vertical padding; compact uses 60%, relaxed 140%. Table cells 0.625remComponent fallbackNo token alias
--neu-tree-table-cell-inline Horizontal cell padding, independent of tree indentation. Table cells var(--neu-space-3)Component fallback--neu-space-3
--neu-tree-table-selected-background Selected-node row background, above alternating stripes. Selected row color-mix(in srgb, currentColor 9%, transparent)Component fallbackNo token alias
--neu-tree-table-virtual-block-size Height of the virtualized hierarchy viewport. Virtualization 24remRoot declarationNo token alias

Shared tokens used

Override these on a local wrapper to affect this example. An override on :root affects other components that use the same token.

Token
Purpose here
Other impact
Default / fallback
--neu-border Normal control and cell borders Shared by other Core consumers; scope the override. rgba(15, 23, 42, 0.08)
--neu-focus-color Visible keyboard-focus outline Shared by other Core consumers; scope the override. var(--neu-primary)
--neu-surface Main field, header or control surface Shared by other Core consumers; scope the override. #ffffff
--neu-surface-2 Secondary surfaces and alternating rows Shared by other Core consumers; scope the override. #f1f5f9
--neu-text Main text and inherited icon color Shared by other Core consumers; scope the override. #0f172a
--neu-text-muted Secondary labels and supporting content Shared by other Core consumers; scope the override. #475569
--neu-space-1 Spacing between content and controls Shared by other Core consumers; scope the override. 0.25rem
--neu-space-3 Spacing between content and controls Shared by other Core consumers; scope the override. 0.75rem