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

Import

component.ts
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
basic.component.ts
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);
}
Interactive playground

Change the settings and try the result.

Device captures shown in English.

Context Menu · android · native capture
AndroidNative screenshot
Context Menu · ios · native capture
iOSNative screenshot

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

NameTypeDefaultBindingDescription
labelstringRequiredInputHuman-readable name for the control, action or group.
itemsreadonly NeuOption[][]InputOrdered data for the component. Use the data contract below and stable, unique item IDs.
hintstring'Long press for actions'InputField guidance shown when no error message is being displayed.
actionsLabelstring'Actions'InputText or accessible name used for action group. It does not perform the action by itself.
closeLabelstring'Dismiss actions'InputText or accessible name used for close. It does not perform the action by itself.
disabledbooleanfalseInputDisables user interaction. Values can still be supplied by the application.

Models

NameTypeDefaultBindingDescription
openbooleanfalseModel · two-wayWhether the presentation or message is requested to be open. Bind a writable signal with [(open)].

Outputs

NamePayloadWhen it emits
openChangebooleanEmits the updated open value. [(open)] binds this output together with its model input.
activatedstringEmits the activated item ID. Your application performs the action.
pressedvoidEmits 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.

model-fields.ts
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

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.