Navigation
Nav
Expose section selection in a compact navigation bar.
Angular NativeiOS / Android0.1.0-beta.1
Import
component.ts
import { NeuNavComponent } from '@neural-ui/native/nav';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.
Basic
Explore an overview, project progress and account preferences. The bottom bar stays in place; your application owns the screens and routing.
View and copy the complete example
basic.component.ts
import { Component, signal } from '@angular/core';
import { NeuButtonComponent } from '@neural-ui/native/button';
import { NeuSwitchComponent } from '@neural-ui/native/switch';
import { NeuCardComponent } from '@neural-ui/native/card';
import { NeuBadgeComponent } from '@neural-ui/native/badge';
import { NeuAvatarComponent } from '@neural-ui/native/avatar';
import { NeuNavComponent } from '@neural-ui/native/nav';
import { NeuProgressBarComponent } from '@neural-ui/native/progress-bar';
import { View, Text, ScrollView } from '@ng-native/components';
import type { NeuNavItem } from '@neural-ui/native/nav';
@Component({
selector: 'app-example',
imports: [NeuButtonComponent, NeuSwitchComponent, NeuCardComponent, NeuBadgeComponent, NeuAvatarComponent, NeuNavComponent, NeuProgressBarComponent, View, Text, ScrollView],
template: `
<view class="workspace-screen">
@switch (destination()) {
@case ('home') {
<scroll-view class="workspace-scroll" keyboardShouldPersistTaps="handled"><view class="workspace-body">
<view class="screen-heading">
<view class="heading-copy">
<text class="eyebrow">NEURAL STUDIO</text>
<text class="screen-title" accessibilityRole="header">Morning, Alex</text>
<text class="muted">Let’s make something great.</text>
</view>
<neu-avatar label="Alex Morgan" size="md" />
</view>
<view class="summary-row">
<view class="summary-tile"><text class="summary-number">03</text><text class="summary-label">Projects</text></view>
<view class="summary-tile"><text class="summary-number">12</text><text class="summary-label">Tasks this week</text></view>
</view>
<text class="section-title">Your focus today</text>
<neu-card title="Mobile launch" description="Next milestone · Friday" variant="outlined">
<neu-badge label="In progress" tone="brand" />
<text class="body-copy">A calmer start for every user.</text>
<neu-progress-bar label="Ready for release" [value]="72" />
<neu-button label="View projects" size="sm" variant="text" (pressed)="destination.set('projects')" />
</neu-card>
<text class="section-title">Up next</text>
<view class="agenda-row">
<view class="agenda-time"><text class="time-value">10:30</text><text class="small-copy">TODAY</text></view>
<view class="agenda-copy"><text class="row-title">Design review</text><text class="muted">With the product team</text></view>
<neu-avatar label="Ada Lovelace" size="sm" tone="neutral" />
</view>
</view></scroll-view>
}
@case ('projects') {
<scroll-view class="workspace-scroll" keyboardShouldPersistTaps="handled"><view class="workspace-body">
<view class="heading-copy">
<text class="eyebrow">YOUR WORKSPACE</text>
<text class="screen-title" accessibilityRole="header">Projects</text>
<text class="muted">A little progress, every day.</text>
</view>
@for (project of projects; track project.id) {
<neu-card [title]="project.title" [description]="project.team" variant="outlined">
<neu-badge [label]="project.status" [tone]="project.tone" />
<neu-progress-bar label="Progress" [value]="project.progress" [tone]="project.tone" />
</neu-card>
}
</view></scroll-view>
}
@case ('account') {
<scroll-view class="workspace-scroll" keyboardShouldPersistTaps="handled"><view class="workspace-body">
<view class="heading-copy">
<text class="eyebrow">MAKE IT YOURS</text>
<text class="screen-title" accessibilityRole="header">Account</text>
</view>
<view class="profile-panel">
<neu-avatar label="Alex Morgan" size="lg" />
<view class="profile-copy"><text class="profile-name">Alex Morgan</text><text class="muted">Product designer</text></view>
<neu-badge label="Studio member" tone="brand" />
</view>
<text class="section-title">Workspace</text>
<view class="settings-panel">
<view class="settings-row"><text class="muted">Team</text><text class="setting-value">Neural Studio</text></view>
<view class="settings-row"><text class="muted">Role</text><text class="setting-value">Designer</text></view>
</view>
<text class="section-title">Preferences</text>
<view class="settings-panel">
<neu-switch label="Email updates" hint="News from your projects" labelPosition="left" [(checked)]="updates" />
<text class="small-copy" accessibilityLiveRegion="polite">{{ updates() ? 'Updates enabled' : 'Updates paused' }}</text>
</view>
<neu-button label="Back to overview" size="sm" variant="outline" (pressed)="destination.set('home')" />
</view></scroll-view>
}
}
<neu-nav label="Main navigation" [items]="destinations" [(value)]="destination" />
</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; }
.workspace-screen { flex: 1; flex-shrink: 1; min-height: 0; background-color: var(--neu-canvas, #f4f5f7); }
.workspace-scroll { flex: 1; flex-shrink: 1; height: 0px; min-height: 0; }
.workspace-body { padding: 24px 20px; gap: 18px; }
.screen-heading { flex-direction: row; align-items: center; gap: 12px; }
.heading-copy { flex: 1; min-width: 0; gap: 5px; }
.eyebrow { font-size: 11px; line-height: 16px; font-weight: 600; letter-spacing: 1.2px; color: var(--neu-muted, #596477); }
.screen-title { font-size: 26px; line-height: 33px; font-weight: 700; color: var(--neu-text, #172033); }
.muted { font-size: 14px; line-height: 20px; color: var(--neu-muted, #596477); }
.summary-row { flex-direction: row; gap: 12px; }
.summary-tile { flex: 1; min-width: 0; padding: 16px; gap: 4px; border-radius: 16px; background-color: var(--neu-surface, #ffffff); }
.summary-number { font-size: 28px; line-height: 34px; font-weight: 700; color: var(--neu-accent, #006ee6); }
.summary-label { font-size: 13px; line-height: 18px; color: var(--neu-muted, #596477); }
.section-title { font-size: 15px; line-height: 21px; font-weight: 600; color: var(--neu-text, #172033); }
.body-copy { font-size: 15px; line-height: 22px; color: var(--neu-text, #172033); }
.agenda-row { flex-direction: row; align-items: center; padding: 16px; gap: 12px; border-radius: 16px; background-color: var(--neu-surface, #ffffff); }
.agenda-time { gap: 3px; }
.time-value { font-size: 15px; line-height: 20px; font-weight: 600; color: var(--neu-accent, #006ee6); }
.agenda-copy { flex: 1; min-width: 0; gap: 3px; }
.row-title { font-size: 15px; line-height: 21px; font-weight: 600; color: var(--neu-text, #172033); }
.small-copy { font-size: 12px; line-height: 18px; color: var(--neu-muted, #596477); }
.profile-panel { align-items: center; gap: 12px; padding: 24px 16px; border-radius: 18px; background-color: var(--neu-surface, #ffffff); }
.profile-copy { align-items: center; gap: 4px; }
.profile-name { font-size: 21px; line-height: 28px; font-weight: 600; color: var(--neu-text, #172033); }
.settings-panel { padding: 16px; gap: 16px; border-radius: 16px; background-color: var(--neu-surface, #ffffff); }
.settings-row { flex-direction: row; align-items: center; justify-content: space-between; gap: 12px; }
.setting-value { flex-shrink: 1; font-size: 14px; line-height: 20px; font-weight: 500; color: var(--neu-text, #172033); }
neu-nav { flex-shrink: 0; }
`,
})
export class ExampleComponent {
readonly destination = signal('home');
readonly updates = signal(true);
readonly destinations: readonly NeuNavItem[] = [
{ id: 'home', label: 'Home', svg: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="m3 10 9-7 9 7v11H3Z"/><path d="M9 21v-8h6v8"/></svg>' },
{ id: 'projects', label: 'Projects', svg: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v10H3Z"/></svg>' },
{ id: 'account', label: 'Account', svg: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round"><circle cx="12" cy="8" r="4"/><path d="M4 21v-2a8 8 0 0 1 16 0v2"/></svg>' },
];
readonly projects = [
{ id: 'mobile', title: 'Mobile launch', team: 'Product team', status: 'In progress', tone: 'brand', progress: 72 },
{ id: 'website', title: 'Website refresh', team: 'Platform team', status: 'In review', tone: 'warning', progress: 90 },
{ id: 'research', title: 'Customer research', team: 'Customer team', status: 'Completed', tone: 'success', progress: 100 },
] as const;
}Interactive playground
Change the settings and try the result.
Device captures shown in English.


API reference
Inputs
| Name | Type | Default | Binding | Description |
|---|---|---|---|---|
| label | string | 'Navigation' | Input | Human-readable name for the control, action or group. |
| items | readonly NeuNavItem[] | [] | Input | Ordered data for the component. Use the data contract below and stable, unique item IDs. |
| disabled | boolean | false | Input | Disables user interaction. Values can still be supplied by the application. |
Models
| Name | Type | Default | Binding | Description |
|---|---|---|---|---|
| value | string | '' | Model · two-way | Current edited value or selected ID(s), using the declared type. Bind a writable signal with [(value)]. |
Outputs
| Name | Payload | When it emits |
|---|---|---|
| valueChange | string | Emits the updated value value. [(value)] binds this output together with its model input. |
| navigate | string | Reports a requested navigation target; application routes remain application-owned. |
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.
NeuNavItem
NeuNavItem.ts
import type { NeuNavItem } from '@neural-ui/native/nav';
import type { NeuOption } from '@neural-ui/native';
// Public definition for reference only. Import this type; do not redeclare it.
export interface NeuNavItem extends NeuOption {
readonly svg?: string;
}| Field | Type | Requirement | Meaning |
|---|---|---|---|
| svg | string | Optional | Optional SVG markup for the item icon. Nav displays it above the destination label; SpeedDial uses it inside the action circle and falls back to the label initial when absent. |
| id | string | Required | Stable, unique identifier used for tracking and selection. |
| label | string | Required | Human-readable item name. |
| description | string | Optional | Optional supporting text; rendering depends on the control. |
| disabled | boolean | Optional | Prevents activating or selecting this item. |
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;
}| Field | Type | Requirement | Meaning |
|---|---|---|---|
| id | string | Required | Stable, unique identifier used for tracking and selection. |
| label | string | Required | Human-readable item name. |
| description | string | Optional | Optional supporting text; rendering depends on the control. |
| disabled | boolean | Optional | Prevents activating or selecting this item. |