Quality
Performance
Keep lists, images and interactions responsive as your screen grows.
Choose the right collection component
- Use Data View for a small collection with a custom item template. Use Virtual List for a long collection that should render through a bounded viewport.
- Keep item identifiers stable when sorting, filtering or loading more data. An item identifier describes the item; it should not change just because the position changed.
Example: a searchable virtual list
Place this screen inside your existing root theme and safe-area provider. The data is created once, and computed derives the filtered collection when the query changes. Selecting an item keeps its original identifier.
import { Component, computed, signal } from '@angular/core';
import { Text, View } from '@ng-native/components';
import { NeuInputComponent } from '@neural-ui/native/input';
import { NeuVirtualListComponent } from '@neural-ui/native/virtual-list';
import type { NeuOption } from '@neural-ui/native/foundation';
@Component({
selector: 'app-contact-list',
imports: [Text, View, NeuInputComponent, NeuVirtualListComponent],
template: `
<view class="content">
<neu-input label="Search contacts" [(value)]="query" />
<neu-virtual-list
[items]="filtered()"
[height]="360"
[estimatedItemHeight]="84"
(selected)="selected.set($event)"
/>
<text>Selected: {{ selected() }}</text>
</view>
`,
styles: `.content { padding: 16px; gap: 12px; }`,
})
export class ContactListComponent {
readonly query = signal('');
readonly selected = signal('');
readonly items: readonly NeuOption[] = Array.from({ length: 500 }, (_, index) => ({
id: 'contact-' + index,
label: 'Contact ' + (index + 1),
description: 'Product team',
}));
readonly filtered = computed(() => {
const query = this.query().trim().toLowerCase();
return query ? this.items.filter(item => item.label.toLowerCase().includes(query)) : this.items;
});
}height bounds the scrolling viewport. estimatedItemHeight is an estimate used by the virtual list, not a fixed row height: adjust it to the content and typography you render. Check large text too. The 500 generated items illustrate the pattern; this is not a performance benchmark.
Avoid oversized images
- Provide image resources appropriate to their display size. A small gallery thumbnail should not need the full-size original.
- Keep the collection data focused on identifiers, labels and image URIs. Avoid duplicating large base64 payloads in every item or recreating the whole collection during each edit.
- Try slow image loading and the largest realistic collection. Check that content stays within the screen while images appear.
Keep state updates focused
Import components from their public entrypoints. Create collection data outside the template and derive filtered or sorted values with computed, as in the example. Keep item templates focused on the visible content; move expensive preparation outside row rendering.
When profiling a slow interaction, separate data preparation, image loading and layout changes. Changing a color or animation duration does not address all three costs.
Check transitions and reduced motion
The theme exposes a duration token for component transitions. Keep transitions short enough to preserve feedback, and check the operating-system reduced-motion setting. Repeatedly open and close menus or dialogs and navigate away while an animation is running.
A repeatable check on your application
- Choose the same device, build and data for each comparison. Use a release build when evaluating the end-user experience.
- Check the first screen load, scroll a long list, filter it and open an overlay. Include slow image loading and large text.
- Identify which action is slow and compare one change at a time. Keep a small reproduction with the relevant component and realistic data.
- Repeat on the other platform and on a representative lower-powered device. Unit tests and browser frames do not measure the native frame rate.