BrickclayDesign System

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.

bk-hierarchical-selectForms and inputsAngular

Preview

A working preview of Hierarchical select in the Brickclay style. Try it.

‹ Back to MainIn Progress
Interact with the preview to see events here.

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.