Skip to main content
Neural Nativev0.1.0-beta.1Documentation

Import

component.ts
import { NeuCascadeSelectComponent } from '@neural-ui/native/cascade-select';

Examples

Import ExampleComponent into its parent and place <app-example /> inside your application’s root neu-theme. The preview supplies the device frame and safe areas; use the root setup from Installation in your app.

A workspace, wherever you are

Move through region, country and office. Back revisits a level; selecting a leaf reveals its destination card.

View and copy the complete example
basic.component.ts
import { Component, signal, computed } from '@angular/core';
import { NeuCardComponent } from '@neural-ui/native/card';
import { NeuBadgeComponent } from '@neural-ui/native/badge';
import { NeuCascadeSelectComponent } from '@neural-ui/native/cascade-select';
import { View, Text, ScrollView } from '@ng-native/components';
import type { NeuTreeNode } from '@neural-ui/native';

@Component({
  selector: 'app-example',
  imports: [NeuCardComponent, NeuBadgeComponent, NeuCascadeSelectComponent, View, Text, ScrollView],
  template: `
    <scroll-view class="product-scroll" keyboardShouldPersistTaps="handled" [showsVerticalScrollIndicator]="true"><view class="product-stack"><view class="product-section"><text class="product-title" accessibilityRole="header">A workspace, wherever you are</text><text class="product-caption">Find your next office one level at a time</text></view>
    <view class="product-surface"><neu-cascade-select label="Office location" placeholder="Choose an office" rootLabel="Regions" [nodes]="locations" [(value)]="office" />
    <text class="product-caption">Region → Country → Office</text></view>
    @if (officeLabel()) { <neu-card [title]="officeLabel()" description="Your next team workspace" variant="outlined"><neu-badge label="Office selected" tone="success" /></neu-card> }</view></scroll-view>
  `,
  styles: `
.actions { gap: 12px; align-items: flex-start; } text { color: var(--neu-text, #172033); font-size: 16px; }

:host { flex: 1; flex-shrink: 1; min-height: 0; }
.product-scroll { flex: 1; flex-shrink: 1; height: 0px; min-height: 0; }
.product-stack { gap: 24px; padding-bottom: 20px; }
.product-section { gap: 12px; }
.product-row { flex-direction: row; align-items: center; gap: 12px; }
.product-copy { flex: 1; min-width: 0; gap: 4px; }
.product-title { color: var(--neu-text, #172033); font-size: 24px; line-height: 30px; font-weight: 600; }
.product-heading { color: var(--neu-text, #172033); font-size: 17px; line-height: 23px; font-weight: 600; }
.product-caption { color: var(--neu-muted, #596477); font-size: 14px; line-height: 20px; }
.product-actions { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 8px; }
.product-surface { gap: 16px; padding: 16px; border-radius: 16px; background-color: var(--neu-surface, #ffffff); border-width: 1px; border-color: var(--neu-border, #a5afbf); }

  `,
})
export class ExampleComponent {
  readonly locations: readonly NeuTreeNode[] = [
    { id: 'europe', label: 'Europe', children: [
      { id: 'spain', label: 'Spain', children: [{ id: 'madrid', label: 'Madrid' }, { id: 'barcelona', label: 'Barcelona' }] },
      { id: 'france', label: 'France', children: [{ id: 'paris', label: 'Paris' }] },
    ] },
    { id: 'americas', label: 'North America', children: [
      { id: 'usa', label: 'United States', children: [{ id: 'austin', label: 'Austin' }, { id: 'new-york', label: 'New York' }] },
    ] },
  ];
  readonly office = signal('');
  readonly officeLabel = computed(() => this.locations.flatMap(region => region.children ?? []).flatMap(country => country.children ?? []).find(office => office.id === this.office())?.label || '');
}
Interactive playground

Change the settings and try the result.

Device captures shown in English.

Cascade Select · android · native capture
AndroidNative screenshot
Cascade Select · ios · native capture
iOSNative screenshot

API reference

Inputs

NameTypeDefaultBindingDescription
nodesreadonly NeuTreeNode[][]InputHierarchical nodes with optional children. Keep IDs unique across the whole tree.
backLabelstring'Back'InputText or accessible name used for back. It does not perform the action by itself.
placeholderstring'Choose item'InputExample or prompt displayed while the value is empty; keep a separate label.
closeLabelstring'Dismiss options'InputText or accessible name used for close. It does not perform the action by itself.
rootLabelstring'All categories'InputHeading for the root level of the cascading category picker.
labelstringRequiredInputHuman-readable name for the control, action or group.
disabledbooleanfalseInputDisables user interaction. Values can still be supplied by the application.
readonlybooleanfalseInputPrevents user editing or selection while retaining the current value.
invalidbooleanfalseInputMarks the control invalid. Your form or application supplies the validation rule.
touchedbooleanfalseInputField interaction state, supplied manually or through Signal Forms.
hintstring''InputField guidance shown when no error message is being displayed.
requiredbooleanfalseInputRequired-field presentation. Define the actual validation rule in your application form.
requiredLabelstring'Required'InputLocalized requirement announced with the field hint when required is true. Defaults to Required; it does not validate the value.
errorstring''InputApplication-provided error message; combine it with the control’s invalid state.

Models

NameTypeDefaultBindingDescription
valuestring''Model · two-wayCurrent edited value or selected ID(s), using the declared type. Bind a writable signal with [(value)].

Outputs

NamePayloadWhen it emits
valueChangestringEmits the updated value value. [(value)] binds this output together with its model input.
touchvoidReports user interaction to the surrounding form or application.

Model state

Bind the signal with [(modelName)] without calling it. Use modelName() to read its value.

model-fields.ts
import { signal } from '@angular/core';

// Fields inside your component class
readonly value = signal<string>('');

Types and data interfaces

Use the imports in your application. The definitions below are provided for reference.

NeuOption

NeuOption.ts
import type { NeuOption } from '@neural-ui/native';

// Public definition for reference only. Import this type; do not redeclare it.
export interface NeuOption {
    readonly id: string;
    readonly label: string;
    readonly description?: string;
    readonly disabled?: boolean;
}
FieldTypeRequirementMeaning
idstringRequiredStable, unique identifier used for tracking and selection.
labelstringRequiredHuman-readable item name.
descriptionstringOptionalOptional supporting text; rendering depends on the control.
disabledbooleanOptionalPrevents activating or selecting this item.

NeuTreeNode

NeuTreeNode.ts
import type { NeuTreeNode } from '@neural-ui/native';
import type { NeuOption } from '@neural-ui/native';

// Public definition for reference only. Import this type; do not redeclare it.
export interface NeuTreeNode extends NeuOption {
    readonly children?: readonly NeuTreeNode[];
}
FieldTypeRequirementMeaning
childrenreadonly NeuTreeNode[]OptionalRecursive child nodes; omit for a leaf.
idstringRequiredStable, unique identifier used for tracking and selection.
labelstringRequiredHuman-readable item name.
descriptionstringOptionalOptional supporting text; rendering depends on the control.
disabledbooleanOptionalPrevents activating or selecting this item.