ComponentUpdated in v15

Cascader

Pick a path through nested options, one column per level.

Installation

Import the class, and @use the entry point in your global styles: without it the component renders unstyled.

import { Component } from '@angular/core';
import { WrCascader } from 'ngwr/cascader';

@Component({ imports: [WrCascader] })
export class MyComponent {}

Basic

Picking a leaf commits the whole path to [(value)] or any Angular form.

<wr-cascader [options]="locations" [(value)]="picked" placeholder="Pick a location" />

locations: WrCascaderOption[] = [
  {
    value: 'us', label: 'United States', children: [
      { value: 'ca', label: 'California', children: [
        { value: 'la', label: 'Los Angeles' },
        { value: 'sf', label: 'San Francisco' },
      ] },
    ],
  },
  // ...
];
Value: [ "us", "ca", "sf" ]

changeOnSelect

Commit on every click, parent levels included.

<wr-cascader
  [options]="locations"
  [(value)]="picked"
  changeOnSelect
  placeholder="Pick any level"
/>
Value: []

Keyboard

The panel has one tab stop: the arrows move inside it, and Tab leaves it.

KeyDoes
ArrowDownArrowUpOn the trigger, opens the panel. In a column, moves to the next or previous option.
HomeEndMoves to the first or last option of the column.
ArrowRightOpens a branch and moves into its column. Mirrored under RTL.
ArrowLeftMoves back to the option the column belongs to. Mirrored under RTL.
A letterMoves to the next option in the column that starts with what you typed.
EnterSpacePicks the option. A leaf commits the path and closes the panel.
EscapeCloses the panel and returns focus to the trigger.
BackspaceOn the closed trigger, clears the path.

Width

The default is 12rem; change it with --wr-cascader-min-width, not a min-width on .wr-cascader__trigger.

API

NameDescriptionTypeDefault
clearLabelAccessible name. Falls back to select.clearSelection, then 'Clear selection'.string | nullnull
optionsrequiredRoot-level options. Each may have children for deeper levels.readonly WrCascaderOption<T>[]—
placeholderPlaceholder shown when no path is selected.string''
ariaLabelAccessible name of the trigger. Falls back to the placeholder, then to select.label — a role="combobox" with nothing selected and no placeholder otherwise has no name at all.string | nullnull
disabledDisable the cascader. Bound automatically from the field's disabled state when used with [formField].booleanfalse
readonlyRefuse changes while the trigger stays focusable and the path still submits. Bound automatically from the field's readonly state when used with [formField]. The panel is where every edit happens, so a read-only cascader simply does not open — there is nothing to browse that is not already on the trigger — and the clear button goes away with it. Mirrored as aria-readonly, which role combobox supports.booleanfalse
sizeControl size — shares the --wr-control-* contract.WrCascaderSize'md'
clearableShow a clear-all (×) button on the trigger when a path is selected.booleantrue
changeOnSelectAllow selecting non-leaf (parent) nodes. When false, only leaves (nodes without children) commit a selection.booleanfalse
separatorSeparator between labels in the trigger display.string'/'
panelClassExtra CSS classes for the column panel's overlay pane. The pane is appended to the overlay container, not to this component, so nothing in the consumer's own template encloses it and no descendant rule written around the trigger can reach it. This input is the only per-instance handle on it. A space-separated string works as well as an array.WrClassInputnull
valueCommitted selection path (full array from root to leaf). Bound by [formField], or two-way via [(value)].unknown[]
(touch)Emitted on blur / commit so a bound field can mark itself touched.void—

Types

NameDescriptionTypeDefault
WrCascaderOption<T>{ value: T, label: string, disabled?: boolean, children?: WrCascaderOption<T>[] }. A node without children is a leaf.interface—

CSS variables

Set these on the component's selector or a wrapper, not on :root: the defaults are declared on ngwr/cascader's own element.

VariableDefaultDeclared on
--wr-cascader-bgvar(--wr-color-surface).wr-cascader +1 variant override
--wr-cascader-bordervar(--wr-border-base).wr-cascader
--wr-cascader-clear-radiusvar(--wr-border-radius-pill).wr-cascader
--wr-cascader-col-bordervar(--wr-border-base).wr-cascader-panel
--wr-cascader-col-gapvar(--wr-space-xs).wr-cascader-panel
--wr-cascader-col-paddingvar(--wr-space-xs).wr-cascader-panel
--wr-cascader-col-width12rem.wr-cascader-panel
--wr-cascader-colorvar(--wr-color-on-surface).wr-cascader +1 variant override
--wr-cascader-font-familyvar(--wr-font-family-base).wr-cascader
--wr-cascader-font-sizevar(--wr-control-font-size-md).wr-cascader +2 variant overrides
--wr-cascader-gapvar(--wr-space-sm).wr-cascader
--wr-cascader-line-heightvar(--wr-control-line-height-md).wr-cascader +2 variant overrides
--wr-cascader-max-height16rem.wr-cascader-panel
--wr-cascader-min-width12rem.wr-cascader
--wr-cascader-opt-active-font-weightvar(--wr-font-weight-medium).wr-cascader-panel
--wr-cascader-opt-fontvar(--wr-control-font-size-md).wr-cascader-panel +2 variant overrides
--wr-cascader-opt-gapvar(--wr-space-sm).wr-cascader-panel
--wr-cascader-opt-pxvar(--wr-space-md).wr-cascader-panel
--wr-cascader-opt-pyvar(--wr-space-sm).wr-cascader-panel +3 variant overrides
--wr-cascader-opt-radiusvar(--wr-border-radius-sm).wr-cascader-panel
--wr-cascader-overlay-padding-topvar(--wr-space-xs).wr-cascader-overlay
--wr-cascader-padding-xvar(--wr-control-padding-x-md).wr-cascader +2 variant overrides
--wr-cascader-padding-yvar(--wr-control-padding-y-md).wr-cascader +2 variant overrides
--wr-cascader-panel-bordervar(--wr-border-base).wr-cascader-panel
--wr-cascader-panel-font-familyvar(--wr-font-family-base).wr-cascader-panel
--wr-cascader-panel-radiusvar(--wr-border-radius-base).wr-cascader-panel
--wr-cascader-radiusvar(--wr-control-radius-md).wr-cascader +2 variant overrides

Dependencies

Angular CDKoverlay, portal
Built onForm, Overlay

See also