Hierarchical select
bk-hierarchical-select: drill into a tree one level at a time (breadcrumb + "Back"), search within the current level, and select any node as either a leaf or (with allowParentSelection) a parent.
Preview
A working preview of Hierarchical select in the Brickclay style. Try it.
Interactive playground
Event log
Interact with the control to see emitted events.
Live code preview
Reflects the toggles above, copy-paste ready.
<bk-hierarchical-select label="Status" placeholder="Select status" [items]="dotItems" labelKey="noteType" valueKey="noteTypeKey" childrenKey="childs" colorKey="color" [(ngModel)]="playgroundValue" [showDots]="true" [inheritColor]="true" [searchable]="true" [clearable]="true" [required]="false" [disabled]="false" [hasError]="false" [allowParentSelection]="false" [multiple]="false" [closeOnSelect]="true" [allSelect]="false" [showParentLabel]="false" [appendToBody]="false" [dropdownPosition]="'bottom'" [backToMainText]="'Back to Main'" (selectionChange)="onPlaygroundSelection($event)" (selectionsChange)="onPlaygroundSelections($event)" (clear)="logFlag('clear', true)"> </bk-hierarchical-select>
Examples
showDots + inheritColor
Dots beside each node, and the control is tinted by the selected node. Only the parents define a colour, "Dispatched" inherits amber from "In Progress", while "Escalated" overrides with red. Value: 21
showDots, inheritColor = false (default)
The same tree with inheritance off. Children without their own color render neutral instead of borrowing the parent's, drill into "In Progress" to compare.
Multiselect (cascade + Select All)
Check "Frontend" to select all of its children at once; uncheck just "React" and "Frontend" shows indeterminate.
// component.ts coloredItems: HierarchicalNode[] = [ { noteTypeKey: 100, noteType: 'Frontend', color: '#DD0031', childs: [ { noteTypeKey: 101, noteType: 'Angular', color: '#DD0031' }, { noteTypeKey: 102, noteType: 'React', color: '#61DAFB' }, { noteTypeKey: 103, noteType: 'Vue', color: '#41B883' }, ], }, // ...Backend, DevOps ]; multiSelectValues: number[] = []; // template - checking "Frontend" also checks Angular/React/Vue (cascade); unchecking // just one of them shows "Frontend" as indeterminate. Select All is scoped to the // level on screen. closeOnSelect=false keeps the panel open across picks. <bk-hierarchical-select label="Technologies" placeholder="Select technologies..." [items]="coloredItems" labelKey="noteType" valueKey="noteTypeKey" childrenKey="childs" colorKey="color" [showDots]="true" [multiple]="true" [allowParentSelection]="true" [allSelect]="true" [closeOnSelect]="false" [(ngModel)]="multiSelectValues"> </bk-hierarchical-select>
Pagination, parent (root) level
20 root items, 8 per page, scroll the open list to the bottom to reveal more.
// component.ts paginationParentItems: HierarchicalNode[] = [ { noteTypeKey: 1, noteType: 'Category 1' }, { noteTypeKey: 2, noteType: 'Category 2' }, // ...20 flat root items, no children ]; paginationParentValue: number | null = null; // template <bk-hierarchical-select label="Category" placeholder="Select a category..." [items]="paginationParentItems" labelKey="noteType" valueKey="noteTypeKey" childrenKey="childs" [paginated]="true" [pageSize]="8" [(ngModel)]="paginationParentValue" (scrollToEnd)="onScrollToEnd()"> </bk-hierarchical-select>
Pagination, child level
3 root categories, each with 18 children, pick any one, then scroll its child list to the bottom to reveal more.
// component.ts paginationChildItems: HierarchicalNode[] = [ { noteTypeKey: 1, noteType: 'Electronics', childs: [ { noteTypeKey: 101, noteType: 'Electronics · Item 1' }, // ...18 children ], }, // ...2 more root categories, each with 18 children of their own ]; paginationChildValue: number | null = null; // template - pagination applies to whichever level is on screen, so drilling // into "Electronics" pages its children the same way the root list would. <bk-hierarchical-select label="Category" placeholder="Select a category..." [items]="paginationChildItems" labelKey="noteType" valueKey="noteTypeKey" childrenKey="childs" [paginated]="true" [pageSize]="8" [(ngModel)]="paginationChildValue" (scrollToEnd)="onScrollToEnd()"> </bk-hierarchical-select>
Usage
bk-hierarchical-select supports hierarchical data with search, "Back to Main" navigation, and displays the selected path (e.g. Tickets > Dispatch > ETA/Status Update).
Use [items], labelKey, valueKey, childrenKey for your tree. Set colorKey (e.g. "color") to style option labels and selected value from the model. Works with ngModel / formControlName; emits selectionChange (full node) and valueChange (value only). Set [paginated]="true" with [pageSize] (default 10) for infinite-scroll pagination, the same scroll-to-bottom interaction as bk-select's own scrollToEnd, no page-number UI. Applies to whichever level is on screen, so both the root list and any drilled-into children list reveal more the same way; listen for (scrollToEnd) if a consumer needs to fetch further items server-side and append them to [items].
Set [multiple]="true" for multi-selection, the CVA value and valueChange become arrays of the selected leaves, and selection is emitted on selectionsChange (array) instead of selectionChange (single node), so a single-select consumer's handler never has to deal with an array it can't actually receive. Add [allowParentSelection]="true" to also let a parent's own checkbox act as a rollup: checking it cascades to every descendant leaf, and it shows indeterminate whenever only some of them are checked. [allSelect]="true" adds a "Select All" row scoped to whichever level is on screen (not the whole tree). [closeOnSelect] defaults to true (closes on every pick, single or multiple); set it to false to keep the panel open across picks, as the multiselect demo above does. A leaf never gets a checkbox of its own, it keeps the same trailing checkmark single-select uses, just no longer limited to one at a time; only a parent's rollup gets a checkbox (tri-state), and only when allowParentSelection is also on. [showParentLabel]="true" prefixes a leaf's label with its immediate parent's in the trigger's chips only (e.g. "Frontend - Angular" instead of just "Angular"), useful once several chips from different parents sit together there. The dropdown rows are unaffected: a row already has the breadcrumb/Back button showing which parent it's under. Whenever multiple is on, a parent with any selected descendants shows a count beside its own label (e.g. "Frontend (2)"), no separate input, it's automatic and visible without drilling in.