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

Import

component.ts
import { NeuToolbarComponent } from '@neural-ui/native/toolbar';

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

A screen toolbar keeps its title on the left and its actions on the right. Search filters the files; the plus creates a local draft.

View and copy the complete example
basic.component.ts
import { Component, signal, computed } from '@angular/core';
import { NeuInputComponent } from '@neural-ui/native/input';
import { NeuToolbarComponent } from '@neural-ui/native/toolbar';
import { View, Text, ScrollView } from '@ng-native/components';
import type { NeuToolbarAction } from '@neural-ui/native/toolbar';

@Component({
  selector: 'app-example',
  imports: [NeuInputComponent, NeuToolbarComponent, View, Text, ScrollView],
  template: `
    <view class="documents-screen">
      <neu-toolbar label="Document actions" [actions]="actions" (activated)="onActivated($event)">
        <text class="toolbar-title" [numberOfLines]="1" ellipsizeMode="tail">Documents</text>
      </neu-toolbar>
      <scroll-view class="documents-scroll" keyboardShouldPersistTaps="handled"><view class="documents-body">
        @if (searching()) {
          <neu-input label="Search documents" placeholder="Name or file type" [(value)]="query" />
        }
        <view class="section-heading">
          <text class="section-title">Recent files</text>
          <text class="file-count">{{ visibleDocuments().length }}</text>
        </view>
        @for (document of visibleDocuments(); track document.id) {
          <view class="document-row">
            <view class="file-symbol"><text class="file-type">{{ document.type }}</text></view>
            <view class="document-copy">
              <text class="document-name" [numberOfLines]="1" ellipsizeMode="tail">{{ document.name }}</text>
              <text class="document-meta">{{ document.detail }}</text>
            </view>
          </view>
        } @empty {
          <text class="empty-copy">No documents match your search.</text>
        }
        <text class="status-copy" accessibilityLiveRegion="polite">{{ status() }}</text>
      </view></scroll-view>
    </view>
  `,
  styles: `
.actions { gap: 12px; align-items: flex-start; } text { color: var(--neu-text, #172033); font-size: 16px; }
:host { flex: 1; min-height: 0; }
.documents-screen { flex: 1; background-color: var(--neu-surface, #ffffff); }
.documents-scroll { flex: 1; min-height: 0; }
.toolbar-title { flex-shrink: 1; color: var(--neu-text, #172033); font-size: 20px; line-height: 26px; font-weight: 600; }
.documents-body { padding: 20px 16px; gap: 8px; }
.section-heading { flex-direction: row; align-items: center; justify-content: space-between; margin-top: 8px; margin-bottom: 8px; }
.section-title { color: var(--neu-muted, #596477); font-size: 13px; line-height: 18px; font-weight: 500; }
.file-count { color: var(--neu-muted, #596477); font-size: 13px; line-height: 18px; }
.document-row { flex-direction: row; align-items: center; gap: 12px; min-height: 76px; padding: 12px 0; border-bottom-width: 1px; border-color: var(--neu-divider, #e4e7ec); }
.file-symbol { width: 44px; height: 48px; border-radius: 10px; background-color: var(--neu-tonal, #e9edfc); align-items: center; justify-content: center; }
.file-type { color: var(--neu-text, #172033); font-size: 11px; font-weight: 600; }
.document-copy { flex: 1; min-width: 0; gap: 4px; }
.document-name { color: var(--neu-text, #172033); font-size: 15px; line-height: 20px; font-weight: 500; }
.document-meta, .status-copy { color: var(--neu-muted, #596477); font-size: 13px; line-height: 18px; }
.status-copy { margin-top: 8px; }
.empty-copy { color: var(--neu-muted, #596477); font-size: 15px; line-height: 22px; padding: 24px 0; }
  `,
})
export class ExampleComponent {
  readonly searching = signal(false);
  readonly query = signal('');
  readonly status = signal('');
  readonly documents = signal([
    { id: 'brief', name: 'Project brief', type: 'PDF', detail: 'Today · 240 KB' },
    { id: 'notes', name: 'Meeting notes', type: 'TXT', detail: 'Yesterday · 12 KB' },
    { id: 'guide', name: 'Brand guidelines', type: 'PDF', detail: 'Monday · 1.8 MB' },
  ]);
  readonly visibleDocuments = computed(() => {
    const query = this.query().trim().toLocaleLowerCase();
    return this.documents().filter(document =>
      (document.name + ' ' + document.type).toLocaleLowerCase().includes(query));
  });
  readonly actions: readonly NeuToolbarAction[] = [
    { id: 'search', label: 'Search files', svg: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round"><circle cx="10.5" cy="10.5" r="6.5"/><path d="m16 16 4 4"/></svg>' },
    { id: 'new', label: 'New document', svg: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round"><path d="M12 5v14M5 12h14"/></svg>' },
  ];
  private nextDraft = 1;
  onActivated(id: string): void {
    if (id === 'search') {
      this.searching.update(value => !value);
      this.query.set('');
    }
    if (id === 'new') {
      const number = this.nextDraft++;
      this.query.set('');
      this.documents.update(documents => [
        { id: 'draft-' + number, name: 'Untitled document ' + number, type: 'TXT', detail: 'Draft · Just now' },
        ...documents,
      ]);
      this.status.set('Draft created on this screen.');
    }
  }
}
Interactive playground

Change the settings and try the result.

Device captures shown in English.

Toolbar · android · native capture
AndroidNative screenshot
Toolbar · ios · native capture
iOSNative screenshot

Personalization

Projected content

Leading content, aligned beside the actions. Project a concise native heading or another compact control. Each action accepts an optional svg; label is its accessible name and remains visible when svg is omitted. The toolbar’s disabled state does not disable your projected controls.

Use native elements from @ng-native/components and public Neural Native controls. Angular styles belong to the component that declares this content.

API reference

Inputs

NameTypeDefaultBindingDescription
labelstring'Toolbar'InputAccessible name announced for the toolbar. It does not render a visible title; project a text element between the toolbar tags for that.
actionsreadonly NeuToolbarAction[][]InputActions on the current screen: id, label, optional svg and disabled. With svg the action is a compact icon button; without it, label is visible. activated emits its id.
disabledbooleanfalseInputDisables the action buttons declared in actions. Any projected interactive controls retain their own disabled state, which your application manages.

Models

This component declares no two-way models.

Outputs

NamePayloadWhen it emits
activatedstringEmits the activated item ID. Your application performs the action.

Types and data interfaces

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

NeuToolbarAction

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

// Public definition for reference only. Import this type; do not redeclare it.
export interface NeuToolbarAction extends NeuOption {
    readonly svg?: string;
}
FieldTypeRequirementMeaning
svgstringOptionalOptional SVG for the action icon. label remains its accessible name. Omit svg to show label as visible text.
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.

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.