Surfaces
Accordion
Organize content into sections that expand when needed.
Import
import { NeuAccordionComponent } from '@neural-ui/native/accordion';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.
Good to know before you order
Read delivery answers within a purchase context and compare single-open with multiple-open behavior. Switching to single-open keeps at most one answer expanded.
View and copy the complete example
import { Component, signal } from '@angular/core';
import { NeuSwitchComponent } from '@neural-ui/native/switch';
import { NeuBadgeComponent } from '@neural-ui/native/badge';
import { NeuAccordionComponent } from '@neural-ui/native/accordion';
import { View, Text, ScrollView } from '@ng-native/components';
import type { NeuOption } from '@neural-ui/native';
@Component({
selector: 'app-example',
imports: [NeuSwitchComponent, NeuBadgeComponent, NeuAccordionComponent, 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">Good to know before you order</text><text class="product-caption">Clear answers, only when you need them</text></view>
<view class="product-surface"><neu-badge label="Delivery and returns" tone="info" /><neu-accordion [items]="questions" [(expanded)]="expanded" [multiple]="multiple()" /></view>
<neu-switch label="Keep several answers open" [checked]="multiple()" (checkedChange)="changeMode($event)" /></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 questions: readonly NeuOption[] = [
{
"id": "shipping",
"label": "When will my order arrive?",
"description": "Orders usually arrive within three working days."
},
{
"id": "returns",
"label": "Can I return an item?",
"description": "Contact support within 30 days of delivery."
}
];
readonly expanded = signal<readonly string[]>(['shipping']);
readonly multiple = signal(true);
changeMode(value: boolean) { this.multiple.set(value); if (!value) this.expanded.update(items => items.slice(0, 1)); }
}One section at a time
Opening one answer closes the previously expanded answer.
View and copy the complete example
import { Component, signal } from '@angular/core';
import { NeuAccordionComponent } from '@neural-ui/native/accordion';
import { View, ScrollView } from '@ng-native/components';
import type { NeuOption } from '@neural-ui/native';
@Component({
selector: 'app-example',
imports: [NeuAccordionComponent, View, ScrollView],
template: `
<scroll-view class="usage-scroll" keyboardShouldPersistTaps="handled"><view class="usage-stack">
<neu-accordion [items]="questions" [(expanded)]="singleExpanded" [multiple]="false" />
</view></scroll-view>
`,
styles: `
.actions { gap: 12px; align-items: flex-start; } text { color: var(--neu-text, #172033); font-size: 16px; }
.usage-scroll { flex: 1; }
.usage-stack { gap: 20px; padding-bottom: 20px; }
.usage-section { gap: 12px; }
.usage-heading { color: var(--neu-text, #172033); font-size: 16px; font-weight: 600; }
.usage-caption { color: var(--neu-muted, #64748b); font-size: 14px; }
.usage-row { flex-direction: row; flex-wrap: wrap; gap: 12px; align-items: center; }
.usage-actions { flex-direction: row; flex-wrap: wrap; gap: 8px; align-items: center; }
`,
})
export class ExampleComponent {
readonly questions: readonly NeuOption[] = [
{
"id": "shipping",
"label": "When will my order arrive?",
"description": "Orders usually arrive within three working days."
},
{
"id": "returns",
"label": "Can I return an item?",
"description": "Contact support within 30 days of delivery."
}
];
readonly expanded = signal<readonly string[]>(['shipping']);
readonly singleExpanded = signal<readonly string[]>([]);
}Interactive playground
Change the settings and try the result.
Device captures shown in English.


API reference
Inputs
| Name | Type | Default | Binding | Description |
|---|---|---|---|---|
| items | readonly NeuOption[] | [] | Input | Each item has a stable id, label for its clickable header, and description for its expandable text body. The disabled flag prevents interaction with that item. The header and body share one surface, separated by a divider while expanded. |
| multiple | boolean | false | Input | Allows multiple choices or files where supported; check the declared model type. |
| disabled | boolean | false | Input | Disables user interaction. Values can still be supplied by the application. |
Models
| Name | Type | Default | Binding | Description |
|---|---|---|---|---|
| expanded | readonly string[] | [] | Model · two-way | IDs of currently expanded sections or nodes. Bind a writable signal with [(expanded)]. |
Outputs
| Name | Payload | When it emits |
|---|---|---|
| expandedChange | readonly string[] | Emits the updated expanded value. [(expanded)] binds this output together with its model input. |
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 expanded = 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. |