Skip to main content
cngx-src documentation

CngxTreeSelect

ComponentPrimaryOnPushNo encapsulationv0.1.0WCAG AA

projects/forms/select/tree-select/tree-select.component.ts

Import#

import { CngxTreeSelect } from '@cngx/forms/select'

Description#

Tree-structured multi-select. Shares popover + commit + focus + announce plumbing with the flat family; adds CngxTreeController + cascade selection. Body is a W3C APG treeview in CngxTreeSelectPanel; ArrowLeft/Right via CngxHierarchicalNav, ArrowUp/Down + Home/End + typeahead via CngxActiveDescendant.

Selection:

  • [cascadeChildren]="false" (default): single-value toggle; indeterminate parents reported via SelectionController.isIndeterminate (controller seeded with childrenFn).
  • [cascadeChildren]="true": parent toggle selects/deselects every descendant atomically. Single selectionChange with action: 'cascade-toggle' carries aggregated added/removed.

https://cngxjs.github.io/cngx/examples/#/forms/select/tree-select/basic-single-level-toggle https://cngxjs.github.io/cngx/examples/#/forms/select/tree-select/cascade-children-parent-toggle-selects-the-whole-subtree https://cngxjs.github.io/cngx/examples/#/forms/select/tree-select/custom-cngxtreeselectnode-template

Metadata#

Host#

Providers#

CNGX_FORM_FIELD_CONTROL
useExisting CngxTreeSelect
CNGX_SELECT_PANEL_VIEW_HOST
useExisting CngxTreeSelect
CNGX_TREE_SELECT_PANEL_HOST
useExisting CngxTreeSelect

Dependencies#

CNGX_TREE_CONTROLLER_FACTORYinject()treeController

Tree controller. Lambdas wrap each input read so the controller sees the current signal value on every call - required inputs like nodeIdFn aren't resolved at factory time.

Relationships

Index#

Inputs#

announceChanges#boolean | null
input()
default null
input()
default null
ariaLabel#string | null
input()
default null, { alias: 'aria-label' }
ariaLabelledBy#string | null
input()
default null, { alias: 'aria-labelledby' }
autofocus#boolean
input()
default false
caretGlyph#TemplateRef | null
default null
cascadeChildren#boolean
input()

When true, parent toggle selects/deselects every descendant atomically; single selectionChange with action: 'cascade-toggle'.

default false
checkGlyph#TemplateRef | null

Forwarded to <cngx-checkbox-indicator [checkGlyph]> on the default row. Custom node templates read selected and render their own.

default null
chipRemoveAriaLabel#string
input()
default this.config.ariaLabels?.chipRemove ?? 'Remove'
clearable#boolean
input()
default false
clearButtonAriaLabel#string
input()
default this.config.ariaLabels?.clearButton ?? 'Reset selection',
clearGlyph#TemplateRef | null
default null
default null
input()
default this.config.commitErrorDisplay
input()
default 'optimistic'
default cngxSelectDefaultCompare as CngxSelectCompareFn<T>,
dashGlyph#TemplateRef | null

Forwarded to <cngx-checkbox-indicator [dashGlyph]>.

default null
disabledInput#boolean
input()
default false, { alias: 'disabled' }
hideCaret#boolean
input()
default !this.config.showCaret
idInput#string | null
input()
default null, { alias: 'id' }
initiallyExpanded#'all' | 'none' | readonly string[] | undefined
input()

Initial expansion seed (one-shot at construction).

label#string
input()
default ''
loading#boolean
input()
default false
input()
default this.config.loadingVariant
nodeIdFn#(value: T, path: readonly number[]) => string
Required

Stable id per node. See CngxTreeControllerOptions.nodeIdFn.

nodes#readonly CngxTreeNode[]

Source tree. Flatten/visibility derive automatically.

default []
panelClass#string | readonly string[] | null
input()
default null
panelWidth#'trigger' | number | null
input()
default this.config.panelWidth
placeholder#string
input()
default ''
popoverPlacement#PopoverPlacement
input()

Popover placement relative to the trigger. Per-instance input wins over CngxSelectConfig.popoverPlacement.

default this.config.popoverPlacement
input()
default this.config.refreshingVariant
requiredInput#boolean
input()
default false, { alias: 'required' }
skeletonRowCount#number
input()
default this.config.skeletonRowCount
default null
tabIndex#number
input()
default 0
twistyCollapseLabel#string
input()
default this.config.ariaLabels?.treeCollapse ?? 'Collapse node',
twistyExpandLabel#string
input()

Localised aria-labels for the twisty button in the default row. Falls back to English. Ignored when *cngxTreeSelectNode is projected.

default this.config.ariaLabels?.treeExpand ?? 'Expand node'
twistyGlyph#TemplateRef | null

Replaces the default twisty glyph in the default node row. Applied to both states unless twistyOpenGlyph is set. Ignored when *cngxTreeSelectNode is projected.

default null
twistyOpenGlyph#TemplateRef | null

Override for the expanded-state twisty glyph. Falls back to twistyGlyph then to (rotated via CSS). Use when expand and collapse glyphs are semantically different shapes.

default null
values#T[]
model()

Multi-value model - the selected subset of T.

default []

Outputs#

cleared#void
output()
closed#void
output()
commitError#unknown
output()
opened#void
output()
openedChange#boolean
output()
retry#void
output()
selectionChange#CngxTreeSelectChange
stateChange#AsyncStatus
output()
values#T[]
model()

Multi-value model - the selected subset of T.

Instance Properties#

ariaLabels#unknown
Readonly
this.config.ariaLabels
commitState#unknown
Readonly

Read-only commit lifecycle view (bridged via CNGX_STATEFUL).

this.commitControllerInstance.state
focused#Signal
Readonly
this.focusState.focused
isCommitting#unknown
Readonly

true when a commit is in flight.

this.commitControllerInstance.isCommitting
keyFn#unknown
Readonly

Membership key for selection. Default identity.

input<((value: T) => unknown) | undefined>(undefined)
keyFnInternal#unknown
ProtectedReadonly

keyFn exposed for template track.

computed<(value: T) => unknown>(
  () => this.keyFn() ?? ((v: T) => v as unknown),
)
labelFn#unknown
Readonly

Display label per node. Falls back to node.label ?? String(value).

input<((value: T) => string) | undefined>(undefined)
retryFn#unknown
Readonly
input<(() => void) | null>(null)
selected#unknown
Readonly

Resolved option-like defs of the current selection. Structural equal (length + pairwise compareWith on value + label string) so chip-strip @for and consumer selected() reads don't cascade-rerender on server refetch.

computed<readonly CngxTreeSelectedItem<T>[]>(
  () => {
    const vals = this.values();
    if (vals.length === 0) {
      return [];
    }
    const out: CngxTreeSelectedItem<T>[] = [];
    const label = this.resolveLabel.bind(this);
    for (const v of vals) {
      out.push({ value: v, label: label(v) });
    }
    return out;
  },
  {
    equal: (a, b) => {
      if (a === b) {
        return true;
      }
      if (a.length !== b.length) {
        return false;
      }
      const eq = this.compareWith();
      for (let i = 0; i < a.length; i++) {
        if (!eq(a[i].value, b[i].value) || a[i].label !== b[i].label) {
          return false;
        }
      }
      return true;
    },
  },
)

Methods#

close#void
focus#void
focus(options?: FocusOptions)
@paramoptions?FocusOptions
handleRetry#void
handleSelect#void
handleSelect(node: FlatTreeNode)

Select path for a tree node. Used both by the CngxTreeSelectPanelHost contract and by the slot context, so custom *cngxTreeSelectNode markup routes through the same cascade + commit plumbing.

@paramnodeFlatTreeNode
isEmpty#boolean
Protected
isIndeterminate#boolean
isIndeterminate(value: T)
@paramvalueT
isSelected#boolean
isSelected(value: T)
@paramvalueT
open#void
toggle#void

HostBindings#

BindingExpression
[id]resolvedId()
[attr.aria-readonly]ariaReadonly()

Structural styles shared across the entire CngxSelect family - imported via styleUrls from every variant (CngxSelect, CngxMultiSelect, CngxCombobox, CngxTypeahead, CngxTreeSelect, CngxReorderableMultiSelect, CngxActionSelect, CngxActionMultiSelect, CngxSelectShell, and the panel components).

All variants run encapsulation: None so the rules below are global; the .cngx-select__* BEM-style class prefix is the namespace.

State modifiers

  • .cngx-option--highlighted on an option row - primary-tinted background marking the keyboard-focused row
  • [aria-disabled='true'] on an option - opacity 0.5 + cursor: not-allowed
  • .cngx-select__option--pending - cursor: progress while a row's commit is in flight
  • .cngx-select__chip-list--reordering - whole-strip cursor: grabbing while a drag is active
  • .cngx-select__chip--dragging on a chip - Trello-style lift (shadow + scale + tilt + accent fill)
  • .cngx-select__chip--drag-over on a chip - vertical drop bar painted on the leading edge via ::before

Variants

Chip-list overflow modes via data-overflow:

  • default - flex-wrap chips across multiple rows
  • data-overflow='scroll-x' - single row + horizontal scroll
  • data-overflow='truncate' - single row + clipped overflow + the .cngx-select__chip-overflow-badge count pill

Error surfaces with two layouts:

  • .cngx-select__error - column-stacked block (message + retry)
  • .cngx-select__error--inline - inline banner above the option list
  • .cngx-select__commit-error - per-commit failure banner

Slots

  • .cngx-select__panel - the floating panel surface (anchor-positioned via position-try-fallbacks)
  • .cngx-select__group-header - uppercase optgroup label
  • .cngx-select__option / .cngx-select__check - option row + the selected-state checkmark
  • .cngx-select__loading / .cngx-select__empty - inline message rows
  • .cngx-select__skeleton / .cngx-select__skeleton-row - first-load shimmer placeholders (static under prefers-reduced-motion)
  • .cngx-select__spinner-wrap / .cngx-select__spinner - first-load spinner ring
  • .cngx-select__loading-bar - first-load top-edge progress bar
  • .cngx-select__refreshing / .cngx-select__refreshing-spinner / .cngx-select__refreshing-dots - subsequent-load indicators
  • .cngx-select__option-spinner / .cngx-select__option-error - per-row commit feedback
  • .cngx-select__chip-list / .cngx-select__chip-overflow-badge - chip strip + overflow count
  • .cngx-select__chip-wrap / .cngx-select__chip-handle - reorderable chip surface + optional drag-handle glyph
  • .cngx-select__error / .cngx-select__error--inline / .cngx-select__error-message / .cngx-select__error-retry / .cngx-select__commit-error - error block, banner, and retry pieces

Inheritance

Tokens are registered top-level in @layer cngx.tokens via @property so any consumer (cngx.theme layer, app layer) can override without learning the type.

Panel surface, every primary-tinted glyph, and every danger-toned error surface delegate to the foundation so a dark-mode swap cascades through the floating panel even when anchor positioning detaches it from the trigger's DOM context:

  • --cngx-select-panel-border -> --cngx-color-border
  • --cngx-select-panel-bg -> --cngx-color-surface
  • --cngx-select-panel-color -> --cngx-color-text
  • --cngx-select-panel-shadow -> --cngx-shadow-md
  • --cngx-select-check-color -> --cngx-color-primary
  • --cngx-select-spinner-color -> --cngx-color-primary
  • --cngx-select-loading-bar-color -> --cngx-color-primary
  • --cngx-select-refreshing-color -> --cngx-color-primary
  • --cngx-select-option-spinner-color -> --cngx-color-primary
  • --cngx-select-option-error-color -> --cngx-color-danger
  • --cngx-select-error-color -> --cngx-color-danger
  • --cngx-select-chip-remove-hover-color -> --cngx-color-danger
  • --cngx-select-chip-drag-bg -> --cngx-color-primary
  • --cngx-select-chip-drop-bar-color -> --cngx-color-primary
  • --cngx-select-trigger-invalid-border-color -> --cngx-color-danger
  • --cngx-select-trigger-invalid-outline-color -> --cngx-color-danger

--cngx-select-panel-min-width is intentionally NOT registered via @property so the anchor-size(width) fallback survives when the consumer doesn't override it; registering it with any initial-value would shadow the var() fallback and break anchor positioning.

Dark mode

Three hooks swap alpha-on-black surfaces (panel shadow, option highlight, spinner track, chip-overflow tint, chip remove-hover tint, chip handle muted, chip drag shadow) plus the skeleton shimmer gradient and the option-spinner track:

  • prefers-color-scheme: dark
  • [data-color-scheme="dark"]
  • .dark class

Foundation-delegated tokens ride the foundation cascade unchanged.

Pair with

  • @cngx/themes/material/select-theme - Material 3 surface treatment across the entire family

Trigger skin for CngxTreeSelect - hierarchical multi-select with cascading children. The host carries .cngx-tree-select; the trigger is a pill-shaped row with placeholder / value summary, optional clear-all button, and a caret. The panel body (the tree of nodes) lives in tree-select-panel.component.css.

State modifiers

  • :focus-visible on .cngx-tree-select__trigger - focus-ring outline + 1px offset
  • [aria-disabled='true'] on the trigger - opacity dim + cursor: not-allowed
  • [aria-invalid='true'] on the trigger - danger border + box-shadow glow at focus-within time

Slots

  • .cngx-tree-select__root - relative-positioned wrapper
  • .cngx-tree-select__trigger - the bordered row
  • .cngx-tree-select__placeholder - placeholder text shown when no values are selected (color via the shared --cngx-select-placeholder-color token, which swaps on dark)
  • .cngx-tree-select__clear-all - reset-all button
  • .cngx-tree-select__caret - panel-state glyph, pushed inline-end

Inheritance

Trigger border + focus ring delegate to the foundation so brand swaps on --cngx-color-border / --cngx-color-primary cascade through:

  • --cngx-tree-select-trigger-border -> --cngx-color-border
  • --cngx-tree-select-focus-ring -> --cngx-color-primary (mixed to 80% via color-mix() for a softer halo)
  • --cngx-select-placeholder-color -> shared family token, dark-mode handled centrally in shared/select-base.css
  • invalid surfaces fall back to --cngx-select-trigger-invalid-* -> --cngx-color-danger

Pair with

  • tree-select-panel.component.css - the body skin sibling
  • @cngx/themes/material/select-theme - Material 3 surface treatment shared across the entire select family

Index#

Surface

--cngx-select-panel-border#*
Default value 1px solid oklch(0.85 0.01 250)

Border shorthand of the dropdown panel. Falls back through --cngx-color-border. inherits: true so the :root delegating value reaches the floating panel host (anchor-positioned, may sit outside the normal DOM flow).

See: [[--cngx-color-border]]

--cngx-select-panel-bg#<color>
Default value oklch(1 0 0)

Background of the dropdown panel. Falls back through --cngx-color-surface.

See: [[--cngx-color-surface]]

--cngx-select-panel-color#*
Default value currentColor

Text color inside the panel. syntax: '*' + initial-value currentColor lets the panel inherit text color from its ancestor by default. Registering as <color> would forbid currentColor since <color> requires a computationally- independent value.

--cngx-select-panel-shadow#*
Default value 0 4px 12px oklch(0 0 0 / 0.12)

Drop-shadow shorthand. Falls back through --cngx-shadow-md. inherits: true so the :root dark-mode override (deeper shadow on dark) reaches the floating panel host.

--cngx-select-placeholder-color#<color>
Default value oklch(0 0 0 / 0.5)

Color of the placeholder text shown when no value is selected.

--cngx-select-caret-color#<color>
Default value oklch(0 0 0 / 0.5)

Color of the dropdown caret glyph shared across every variant. Muted by default to mirror the placeholder token; the Material bridge maps it to --mat-sys-on-surface-variant. inherits: true so a trigger-level override reaches the glyph element.

--cngx-select-clear-color#<color>
Default value oklch(0 0 0 / 0.5)

Color of the clear-button glyph shared across every variant. Tracks the same muted default as the caret so both trigger affordances read uniformly. inherits: true so a trigger-level override reaches the glyph element.

--cngx-tree-select-trigger-border#*
Default value 1px solid oklch(0.85 0.01 250)

Border shorthand of the trigger. inherits: true so the :root delegating value reaches the trigger host.

--cngx-tree-select-trigger-bg#<color>
Default value transparent

Background of the trigger.

Layout

--cngx-select-panel-radius#*
Default value 0.25rem

Corner radius of the dropdown panel.

--cngx-select-panel-padding#*
Default value 0.25rem

Inner padding of the panel.

--cngx-select-panel-max-height#*
Default value 16rem

Maximum height before vertical scrolling kicks in.

--cngx-select-option-padding#*
Default value 0.375rem 0.5rem

Padding shorthand of each option row.

--cngx-select-option-min-height#*
Default value auto

Minimum height of an option row - defaults to auto so dense rows stay compact.

--cngx-select-option-radius#*
Default value 0.125rem

Corner radius of an option row.

--cngx-select-caret-size#*
Default value 1.25em

Font-size of the dropdown caret glyph shared across every variant.

--cngx-select-chip-gap#*
Default value 0.25rem

Gap between chips inside the trigger chip list.

--cngx-select-chip-wrap-radius#*
Default value 0.25rem

Corner radius of the reorderable chip wrap container.

--cngx-select-chip-wrap-gap#*
Default value 0.25rem

Gap between the chip body and any projected drag handle.

--cngx-tree-select-min-width#*
Default value 10rem

Minimum inline size of the trigger.

--cngx-tree-select-trigger-gap#*
Default value 0.5rem

Gap between the value summary, clear button, and caret.

--cngx-tree-select-trigger-height#*
Default value 2.25rem

Minimum block size of the trigger.

--cngx-tree-select-trigger-padding#*
Default value 0.25rem 0.5rem

Padding shorthand of the trigger.

--cngx-tree-select-trigger-radius#*
Default value 0.25rem

Corner radius of the trigger.

State / Highlighted

--cngx-select-option-highlight-bg#<color>
Default value oklch(0.66 0.19 50 / 0.1)

Background of the keyboard-highlighted option row. Defaults to a low-alpha tint of --cngx-color-primary so the highlight reads as brand-accented without competing with selection state.

See: [[--cngx-color-primary]]

State / Selected

--cngx-select-check-color#<color>
Default value oklch(0.66 0.19 50)

Color of the selected-option checkmark glyph. Falls back through --cngx-color-primary.

See: [[--cngx-color-primary]]

State / Disabled

--cngx-select-disabled-opacity#<number>
Default value 0.5

Opacity multiplier applied when the trigger is disabled. Shared family-wide so every variant dims its disabled trigger identically.

--cngx-tree-select-disabled-opacity#<number>
Default value 0.5

Opacity multiplier applied when the trigger is disabled.

State / Loading

--cngx-select-skeleton-gap#*
Default value 0.25rem

Vertical gap between skeleton placeholder rows.

--cngx-select-skeleton-padding#*
Default value 0.25rem

Padding around the skeleton placeholder block.

--cngx-select-skeleton-row-height#*
Default value 1.75rem

Height of each skeleton placeholder row.

--cngx-select-skeleton-row-radius#*
Default value 0.125rem

Corner radius of each skeleton placeholder row.

--cngx-select-spinner-padding#*
Default value 1rem

Padding around the first-load spinner wrapper.

--cngx-select-spinner-size#*
Default value 1.5rem

Diameter of the first-load spinner ring.

--cngx-select-spinner-border#*
Default value 2px solid oklch(0 0 0 / 0.15)

Track stroke of the first-load spinner ring. inherits: true so the :root dark-mode override (alpha-on-white on dark) reaches the spinner inside the floating panel.

--cngx-select-spinner-color#<color>
Default value oklch(0.66 0.19 50)

Indicator stroke of the first-load spinner ring. Falls back to --cngx-color-primary.

--cngx-select-loading-bar-height#<length>
Default value 3px

Height of the first-load loading bar.

--cngx-select-loading-bar-color#<color>
Default value oklch(0.66 0.19 50)

Color of the first-load loading bar. Falls back to --cngx-color-primary.

State / Refreshing

--cngx-select-refreshing-height#<length>
Default value 2px

Height of the subsequent-load refreshing bar.

--cngx-select-refreshing-color#<color>
Default value oklch(0.66 0.19 50)

Color of the refreshing bar gradient. Falls back to --cngx-color-primary.

--cngx-select-refreshing-spinner-padding#*
Default value 0.25rem

Padding around the refreshing spinner wrapper.

--cngx-select-refreshing-dots-gap#*
Default value 0.25rem

Gap between the three refreshing dots.

--cngx-select-refreshing-dots-padding#*
Default value 0.375rem

Padding around the refreshing dots block.

--cngx-select-refreshing-dot-size#*
Default value 0.375rem

Diameter of each refreshing dot.

--cngx-select-refreshing-dot-color#*
Default value currentColor

Color of each refreshing dot.

State / Commit

--cngx-select-option-spinner-size#*
Default value 0.875rem

Diameter of the per-row commit spinner.

--cngx-select-option-spinner-color#<color>
Default value oklch(0.66 0.19 50)

Indicator stroke of the per-row commit spinner.

--cngx-select-option-error-color#<color>
Default value oklch(0.6 0.18 25)

Glyph color of the per-row commit error indicator. Falls back to --cngx-color-danger.

--cngx-select-commit-error-padding#*
Default value 0.375rem 0.5rem

Padding of the commit error banner.

--cngx-select-commit-error-radius#*
Default value 0.125rem

Corner radius of the commit error banner.

State / Overflow

--cngx-select-chip-overflow-badge-bg#<color>
Default value oklch(0 0 0 / 0.08)

Background of the chip overflow badge shown in truncate overflow mode.

--cngx-select-chip-overflow-badge-color#<color>
Default value oklch(0 0 0 / 0.6)

Text color of the chip overflow badge.

State / Remove

--cngx-select-chip-remove-size#*
Default value 1.25rem

Hit-target diameter of the chip remove button inside a reorderable chip wrap.

--cngx-select-chip-remove-hover-bg#<color>
Default value oklch(0 0 0 / 0.12)

Background tint of the chip remove button on hover.

--cngx-select-chip-remove-hover-color#<color>
Default value oklch(0.6 0.18 25)

Foreground color of the chip remove button on hover. Falls back to --cngx-color-danger.

State / Reorder

--cngx-select-chip-handle-color#<color>
Default value oklch(0.5 0.01 250)

Color of the optional projected drag-handle glyph.

--cngx-select-chip-handle-size#*
Default value 0.75rem

Font-size of the optional projected drag-handle glyph.

State / Dragging

--cngx-select-chip-drag-shadow#*
Default value 0 8px 20px oklch(0 0 0 / 0.28)

Drop-shadow of the chip lifted into the dragging state. inherits: true so the :root dark-mode override (deeper shadow on dark) reaches the chip while it's being dragged.

--cngx-select-chip-drag-bg#<color>
Default value oklch(0.66 0.19 50)

Background of the chip lifted into the dragging state. Falls back to --cngx-color-primary.

See: [[--cngx-color-primary]]

--cngx-select-chip-drag-color#<color>
Default value oklch(1 0 0)

Text color of the chip lifted into the dragging state.

--cngx-select-chip-drag-scale#<number>
Default value 1.06

Scale multiplier of the dragging chip - Trello-style lift.

--cngx-select-chip-drag-tilt#<angle>
Default value -1.5deg

Rotation tilt applied to the dragging chip - Trello-style lift.

--cngx-select-chip-drop-bar-width#<length>
Default value 3px

Width of the drop-indicator bar between chips.

--cngx-select-chip-drop-bar-color#<color>
Default value oklch(0.66 0.19 50)

Color of the drop-indicator bar between chips. Falls back to --cngx-color-primary.

State / Error

--cngx-select-error-gap#*
Default value 0.5rem

Gap between the error message and the retry button.

--cngx-select-error-padding#*
Default value 0.5rem 0.75rem

Padding of the panel-wide error block.

--cngx-select-error-color#<color>
Default value oklch(0.6 0.18 25)

Text color of every error surface. Falls back to --cngx-color-danger.

See: [[--cngx-color-danger]]

--cngx-select-error-inline-padding#*
Default value 0.375rem 0.5rem

Padding of the inline error banner shown above the option list.

--cngx-select-error-inline-radius#*
Default value 0.125rem

Corner radius of the inline error banner.

--cngx-select-error-retry-border#*
Default value 1px solid currentColor

Border shorthand of the error retry button.

State / Trigger invalid

--cngx-select-trigger-invalid-border-color#<color>
Default value oklch(0.6 0.18 25)

Border color painted on the trigger wrapper when aria-invalid="true". Defaults track --cngx-color-danger via the delegating :root entry below.

--cngx-select-trigger-invalid-border-width#<length>
Default value 1px

Border width painted on the trigger wrapper when aria-invalid="true".

--cngx-select-trigger-invalid-outline-color#<color>
Default value oklch(0.6 0.18 25)

Outline color layered on the invalid trigger when focus is inside it. Defaults track --cngx-color-danger via the delegating :root entry below.

--cngx-select-trigger-invalid-glow#*
Default value 0 0 0 3px oklch(0.6 0.18 25 / 0.2)

Soft halo layered behind the invalid trigger at focus time. Authored as a box-shadow so it composes with any consumer-supplied focus outline.

State / Focus

--cngx-tree-select-focus-ring#*
Default value 2px solid oklch(0.66 0.19 50 / 0.8)

Focus-ring outline shorthand. Falls back to --cngx-color-primary. inherits: true so the :root delegating value reaches the trigger host.

See: [[--cngx-color-primary]]

State / Clear

--cngx-tree-select-clear-size#*
Default value 1.25rem

Hit-target diameter of the clear-all button.

Material theme

import { ChangeDetectionStrategy, Component, ViewEncapsulation, signal } from '@angular/core';

import { CngxTreeSelect } from '@cngx/forms/select';
import type { CngxTreeNode } from '@cngx/utils';

/**
 * `CngxTreeSelect` rendered against a Material 3 palette via the published
 * `@cngx/themes/material/select-theme` bridge.
 *
 * The stylesheet builds a real M3 theme: `mat.theme` emits the `--mat-sys-*`
 * system tokens, then `select.theme($theme)` routes every `--cngx-select-*`
 * token onto its Material counterpart, so the trigger, panel surface, and
 * selected-node tones inherit the palette with no per-instance overrides.
 * `ViewEncapsulation.None` lets the global `html` theme and the
 * `:where(cngx-tree-select)` bridge rules reach both the trigger and the
 * top-layer panel.
 */
@Component({
  selector: 'app-root',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  imports: [CngxTreeSelect],
  styleUrl: './material-theme.component.scss',
  template: `
    <div class="demo">
      <cngx-tree-select
        [label]="'Regions'"
        [nodes]="nodes"
        [nodeIdFn]="nodeIdFn"
        [(values)]="values"
        [cascadeChildren]="true"
        placeholder="Pick regions…"
      />
      <p class="demo__readout">Selected: {{ values().join(', ') || '—' }}</p>
    </div>
  `,
})
export class MaterialThemeExample {
  protected readonly values = signal<string[]>([]);

  protected readonly nodeIdFn = (value: string): string => value;

  protected readonly nodes: CngxTreeNode<string>[] = [
    {
      value: 'europe',
      label: 'Europe',
      children: [
        { value: 'austria', label: 'Austria' },
        { value: 'germany', label: 'Germany' },
        { value: 'france', label: 'France' },
      ],
    },
    {
      value: 'americas',
      label: 'Americas',
      children: [
        { value: 'usa', label: 'United States' },
        { value: 'canada', label: 'Canada' },
        { value: 'brazil', label: 'Brazil' },
      ],
    },
  ];
}
export { MaterialThemeExample as AppComponent };