Navigation
Context Menu
Offer actions relevant to the current item or task.
Import
import { NeuContextMenuComponent } from '@neural-ui/native/context-menu';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.
Keep actions close to their object
Tap the project to open its summary or use the contextual menu for related actions. The three-dot trigger exposes the same menu without requiring a long press.
View and copy the complete example
import { Component, signal } from '@angular/core';
import { NeuButtonComponent } from '@neural-ui/native/button';
import { NeuInputComponent } from '@neural-ui/native/input';
import { NeuCardComponent } from '@neural-ui/native/card';
import { NeuAvatarComponent } from '@neural-ui/native/avatar';
import { NeuContextMenuComponent } from '@neural-ui/native/context-menu';
import { NeuProgressBarComponent } from '@neural-ui/native/progress-bar';
import { View, Text, ScrollView } from '@ng-native/components';
@Component({
selector: 'app-example',
imports: [NeuButtonComponent, NeuInputComponent, NeuCardComponent, NeuAvatarComponent, NeuContextMenuComponent, NeuProgressBarComponent, 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">Keep actions close to their object</text><text class="product-caption">Tap to open, hold for more options</text></view>
<neu-context-menu label="Mobile launch" hint="Hold this project or tap the three dots" actionsLabel="Project actions" [items]="actions" [(open)]="menuOpen" (pressed)="action.set('details')" (activated)="action.set($event)"><neu-avatar label="Mobile launch" size="md" /></neu-context-menu>@if (action() === 'details') { <neu-card title="Project summary" description="Mobile launch · Friday milestone" variant="outlined"><view class="product-section"><neu-progress-bar label="Release readiness" [value]="72" /><text>Prepare the onboarding flow and final release notes.</text></view></neu-card> }
@if (action() === 'invite') { <view class="product-surface"><text class="product-heading">Invite a teammate</text><neu-input label="Teammate name" [(value)]="invitee" /><view class="product-actions"><neu-button label="Preview invitation" size="sm" [disabled]="!invitee().trim()" (pressed)="prepare()" /></view>@if (prepared()) { <text class="product-caption">Invitation prepared locally for {{ prepared() }}</text> }</view> }</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 actions = [{ id: 'details', label: 'Open details', description: 'View the project summary' }, { id: 'invite', label: 'Prepare invitation', description: 'Choose a teammate for this project' }, { id: 'archive', label: 'Archive project', disabled: true }];
readonly action = signal('');
readonly invitee = signal('');
readonly prepared = signal('');
prepare() { if (this.invitee().trim()) this.prepared.set(this.invitee().trim()); }
readonly menuOpen = signal(false);
}Change the settings and try the result.
Device captures shown in English.


Personalization
Projected content
Inside the long-press target, before its label and hint. Add a thumbnail or avatar; avoid nested pressable controls inside this target.
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
| Name | Type | Default | Binding | Description |
|---|---|---|---|---|
| label | string | Required | Input | Human-readable name for the control, action or group. |
| items | readonly NeuOption[] | [] | Input | Ordered data for the component. Use the data contract below and stable, unique item IDs. |
| hint | string | 'Long press for actions' | Input | Field guidance shown when no error message is being displayed. |
| actionsLabel | string | 'Actions' | Input | Text or accessible name used for action group. It does not perform the action by itself. |
| closeLabel | string | 'Dismiss actions' | Input | Text or accessible name used for close. It does not perform the action by itself. |
| disabled | boolean | false | Input | Disables user interaction. Values can still be supplied by the application. |
Models
| Name | Type | Default | Binding | Description |
|---|---|---|---|---|
| open | boolean | false | Model · two-way | Whether the presentation or message is requested to be open. Bind a writable signal with [(open)]. |
Outputs
| Name | Payload | When it emits |
|---|---|---|
| openChange | boolean | Emits the updated open value. [(open)] binds this output together with its model input. |
| activated | string | Emits the activated item ID. Your application performs the action. |
| pressed | void | Emits the native press event when an enabled action is activated. |
Model state
Bind the signal with [(modelName)] without calling it. Use modelName() to read its value.
import { signal } from '@angular/core';
// Fields inside your component class
readonly open = signal<boolean>(false);Types and data interfaces
Use the imports in your application. The definitions below are provided for reference.
NeuOption
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. |