# Nav

Use `ui-nav` for sidebars, workspace rails, settings navigation, and other structured navigation surfaces where a flat menu is not enough. It manages rendering and tree behavior for navigation rows, while the surrounding app handles routing or state updates when a node is selected.

## Import
```ts
import { NavComponent, type NavNode } from 'ui';
```

## Basic side navigation
```ts
import { Component } from '@angular/core';
import { NavComponent, type NavNode } from 'ui';

@Component({
  selector: 'app-nav-basic-demo',
  standalone: true,
  imports: [NavComponent],
  template: `
    <div
      style="width:100%;max-width:18rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
    >
      <ui-nav [items]="items" />
    </div>
  `,
})
export class NavBasicDemoComponent {
  protected readonly items: NavNode[] = [
    { id: 'home', label: 'Home', icon: 'home' },
    { id: 'activity', label: 'Activity', icon: 'history', selected: true },
    { id: 'files', label: 'Files', icon: 'folder' },
    { id: 'settings', label: 'Settings', icon: 'settings' },
  ];
}
```

## Appearance, variant, and shape
```ts
import { Component } from '@angular/core';
import { NavComponent, type NavNode } from 'ui';

const items: NavNode[] = [
  { id: 'overview', label: 'Overview', icon: 'book', selected: true },
  { id: 'reports', label: 'Reports', icon: 'document' },
  { id: 'automation', label: 'Automation', icon: 'design_ideas' },
];

@Component({
  selector: 'app-nav-appearance-demo',
  standalone: true,
  imports: [NavComponent],
  template: `
    <div style="display:flex;flex-direction:column;gap:1rem;width:100%;max-width:20rem">
      <div
        style="padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <div style="margin:0 0 0.75rem;font-size:0.9375rem;font-weight:600">
          Subtle workspace rail
        </div>
        <ui-nav [items]="items" appearance="subtle" variant="primary" />
      </div>

      <div
        style="padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <div style="margin:0 0 0.75rem;font-size:0.9375rem;font-weight:600">
          Filled secondary rail
        </div>
        <ui-nav [items]="items" appearance="filled" variant="secondary" shape="circular" />
      </div>
    </div>
  `,
})
export class NavAppearanceDemoComponent {
  protected readonly items = items;
}
```

## Deep navigation trees
```ts
import { Component } from '@angular/core';
import { NavComponent, type NavNode } from 'ui';

@Component({
  selector: 'app-nav-deep-tree-demo',
  standalone: true,
  imports: [NavComponent],
  template: `
    <div
      style="width:100%;max-width:19rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
    >
      <ui-nav [items]="items" [showSelectionIndicator]="true" indicatorPosition="vertical" />
    </div>
  `,
})
export class NavDeepTreeDemoComponent {
  protected readonly items: NavNode[] = [
    {
      id: 'workspace',
      label: 'Workspace',
      icon: 'building_bank_toolbox',
      hasChildren: true,
      expanded: true,
      children: [
        {
          id: 'projects',
          label: 'Projects',
          icon: 'folder',
          hasChildren: true,
          expanded: true,
          children: [
            {
              id: 'alpha',
              label: 'Project Alpha',
              icon: 'document',
              hasChildren: true,
              expanded: true,
              children: [
                { id: 'overview', label: 'Overview', selected: true },
                { id: 'tasks', label: 'Tasks' },
                { id: 'releases', label: 'Releases' },
              ],
            },
            {
              id: 'beta',
              label: 'Project Beta',
              icon: 'document',
              hasChildren: true,
              children: [
                { id: 'overview-beta', label: 'Overview' },
                { id: 'files-beta', label: 'Files' },
              ],
            },
          ],
        },
        {
          id: 'operations',
          label: 'Operations',
          icon: 'settings',
          hasChildren: true,
          children: [
            { id: 'incidents', label: 'Incidents' },
            { id: 'runbooks', label: 'Runbooks' },
          ],
        },
      ],
    },
  ];
}
```

## Sections and dividers
```ts
import { Component } from '@angular/core';
import { NavComponent, type NavNode } from 'ui';

@Component({
  selector: 'app-nav-sections-demo',
  standalone: true,
  imports: [NavComponent],
  template: `
    <div
      style="width:100%;max-width:19rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
    >
      <ui-nav [items]="items" />
    </div>
  `,
})
export class NavSectionsDemoComponent {
  protected readonly items: NavNode[] = [
    { id: 'main-header', label: 'Main', isSectionHeader: true },
    { id: 'home', label: 'Home', icon: 'home', selected: true },
    { id: 'search', label: 'Search', icon: 'search' },
    { id: 'divider-1', label: 'divider', isDivider: true },
    { id: 'work-header', label: 'Workspaces', isSectionHeader: true },
    {
      id: 'design-system',
      label: 'Design system',
      icon: 'color',
      hasChildren: true,
      expanded: true,
      children: [
        { id: 'components', label: 'Components' },
        { id: 'guidelines', label: 'Guidelines' },
      ],
    },
    {
      id: 'platform',
      label: 'Platform',
      icon: 'apps',
      hasChildren: true,
      children: [
        { id: 'deployments', label: 'Deployments' },
        { id: 'feature-flags', label: 'Feature flags' },
      ],
    },
    { id: 'divider-2', label: 'divider', isDivider: true },
    { id: 'admin-header', label: 'Administration', isSectionHeader: true },
    { id: 'billing', label: 'Billing', icon: 'wallet' },
    { id: 'security', label: 'Security', icon: 'shield', disabled: true },
  ];
}
```

## Content templates with badges
```ts
import { CommonModule } from '@angular/common';
import { Component, TemplateRef, viewChild } from '@angular/core';
import { NavComponent, type NavNode } from 'ui';

@Component({
  selector: 'app-nav-content-template-demo',
  standalone: true,
  imports: [CommonModule, NavComponent],
  template: `
    <div
      style="width:100%;max-width:19rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
    >
      <ui-nav [items]="items" [contentTemplate]="contentTemplateRef() ?? null" />
    </div>

    <ng-template #navContentTemplate let-node>
      <div
        style="display:flex;align-items:center;justify-content:space-between;gap:0.5rem;width:100%"
      >
        <span>{{ node.label }}</span>
        <span
          style="min-width:1.5rem;padding:0.125rem 0.45rem;border-radius:999px;background:var(--color-neutral-background3-rest);font-size:0.75rem;text-align:center"
        >
          {{ getCount(node.id) }}
        </span>
      </div>
    </ng-template>
  `,
})
export class NavContentTemplateDemoComponent {
  protected readonly items: NavNode[] = [
    { id: 'inbox', label: 'Inbox', icon: 'mail', selected: true },
    { id: 'mentions', label: 'Mentions', icon: 'person_accounts' },
    { id: 'drafts', label: 'Drafts', icon: 'document' },
    { id: 'archive', label: 'Archive', icon: 'archive' },
  ];

  protected contentTemplateRef = viewChild<TemplateRef<any>>('navContentTemplate');

  protected getCount(id: string): number {
    const counts: Record<string, number> = {
      inbox: 12,
      mentions: 4,
      drafts: 2,
      archive: 31,
    };
    return counts[id] ?? 0;
  }
}
```

## Quick actions on nodes
```ts
import { CommonModule } from '@angular/common';
import { Component, TemplateRef, signal, viewChild } from '@angular/core';
import { ButtonComponent, NavComponent, type NavNode } from 'ui';

@Component({
  selector: 'app-nav-quick-actions-demo',
  standalone: true,
  imports: [CommonModule, ButtonComponent, NavComponent],
  template: `
    <div
      style="display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start;width:100%;max-width:46rem"
    >
      <div
        style="flex:0 0 19rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <ui-nav
          [items]="items"
          [showQuickActions]="true"
          [quickActionsTemplate]="quickActionsTemplateRef() ?? null"
        />
      </div>

      <div
        style="flex:1 1 16rem;padding:0.875rem 1rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background2-rest)"
      >
        <p
          style="margin:0 0 0.5rem;font-size:0.75rem;font-weight:600;letter-spacing:0.06em;text-transform:uppercase;color:var(--color-neutral-foreground2-rest)"
        >
          Last action
        </p>
        <div style="font-size:0.875rem;line-height:1.5;color:var(--color-neutral-foreground-rest)">
          {{ lastAction() || 'No quick action used yet.' }}
        </div>
      </div>
    </div>

    <ng-template #navQuickActionsTemplate let-node>
      <div style="display:flex;gap:0.375rem">
        <ui-button
          appearance="tint"
          variant="secondary"
          icon="pin"
          (click)="onQuickAction('Pin', node); $event.stopPropagation()"
        />
        <ui-button
          appearance="tint"
          variant="danger"
          icon="delete"
          (click)="onQuickAction('Remove', node); $event.stopPropagation()"
        />
      </div>
    </ng-template>
  `,
})
export class NavQuickActionsDemoComponent {
  protected readonly items: NavNode[] = [
    { id: 'backlog', label: 'Backlog', icon: 'list' },
    { id: 'active-sprint', label: 'Active sprint', icon: 'rocket', selected: true },
    { id: 'review-queue', label: 'Review queue', icon: 'edit' },
  ];

  protected readonly lastAction = signal('');
  protected quickActionsTemplateRef = viewChild<TemplateRef<any>>('navQuickActionsTemplate');

  protected onQuickAction(action: string, node: NavNode): void {
    this.lastAction.set(`${action} on "${node.label}"`);
  }
}
```

## Accessibility

### Navigation semantics
`ui-nav` renders its content inside a navigation region and uses tree-node semantics for hierarchical items. Section headers and dividers remain non-interactive, while actual navigation rows expose button-like interaction through the underlying tree node model.

### Keyboard behavior
Keyboard behavior follows the tree-node interaction model.

| Key | Action |
| --- | --- |
| Tab | Moves focus into or out of the navigation region according to document order. |
| Enter / Space | Activates the focused row according to its click behavior. |
| Arrow keys | Move between rows and expand or collapse nested items through the underlying tree navigation model. |

### Selected item handling
Selected nodes should reflect the current location or active workspace context. When `autoScrollToSelected` is enabled, the component will attempt to bring the selected item into view after the data changes.
