Feedback
Notification Center
Group notifications and expose actions for their read state.
Import
import { NeuNotificationCenterComponent } from '@neural-ui/native/notification-center';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.
Your team, in sync
Open an update to mark it as read and reveal its details below the inbox. Notices stay available after reading.
View and copy the complete example
import { Component, signal, computed } from '@angular/core';
import { NeuButtonComponent } from '@neural-ui/native/button';
import { NeuCardComponent } from '@neural-ui/native/card';
import { NeuNotificationCenterComponent } from '@neural-ui/native/notification-center';
import { View, Text, ScrollView } from '@ng-native/components';
import type { NeuOption } from '@neural-ui/native';
@Component({
selector: 'app-example',
imports: [NeuButtonComponent, NeuCardComponent, NeuNotificationCenterComponent, 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">Your team, in sync</text><text class="product-caption">Product workspace</text></view>
<neu-notification-center label="Team updates" [items]="notifications" [(readIds)]="readIds" (activated)="selected.set($event)" />
@if (openedNotification(); as notification) {
<neu-card [title]="notification.label" [description]="notification.description || ''" variant="outlined"><view class="product-section">
<text>{{ notification.id === 'invite' ? 'Open the project workspace to accept your invitation and meet the team.' : 'The release review is complete. Your team can now prepare the next build.' }}</text>
<neu-button label="Close details" size="sm" variant="text" (pressed)="selected.set('')" />
</view></neu-card>
}</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 notifications: readonly NeuOption[] = [
{
"id": "invite",
"label": "New project invitation",
"description": "Ada invited you to Mobile launch."
},
{
"id": "review",
"label": "Review completed",
"description": "Your release notes are ready."
}
];
readonly readIds = signal<readonly string[]>(['review']);
readonly selected = signal('');
readonly openedNotification = computed(() => this.notifications.find(item => item.id === this.selected()));
}Interactive playground
Change the settings and try the result.
Device captures shown in English.


API reference
Inputs
| Name | Type | Default | Binding | Description |
|---|---|---|---|---|
| label | string | 'Notifications' | 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. |
| disabled | boolean | false | Input | Disables user interaction. Values can still be supplied by the application. |
| markAllLabel | string | 'Mark all read' | Input | Text or accessible name used for mark all as read. It does not perform the action by itself. |
| unreadLabel | string | 'Unread' | Input | Text or accessible name used for unread notifications. It does not perform the action by itself. |
| emptyLabel | string | 'No notifications' | Input | Text or accessible name used for empty state. It does not perform the action by itself. |
Models
| Name | Type | Default | Binding | Description |
|---|---|---|---|---|
| readIds | readonly string[] | [] | Model · two-way | IDs of notifications marked as read. Bind a writable signal with [(readIds)]. |
Outputs
| Name | Payload | When it emits |
|---|---|---|
| readIdsChange | readonly string[] | Emits the updated readIds value. [(readIds)] binds this output together with its model input. |
| activated | string | Emits the activated item ID. Your application performs the action. |
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 readIds = signal<readonly string[]>([]);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. |