Data & media
Stats Card
Highlight a metric, its label and supporting context.
Import
import { NeuStatsCardComponent } from '@neural-ui/native/stats-card';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.
Creative momentum
Use StatsCard for a weekly studio summary. The highlighted metric includes an accessible five-day chart; selecting a period updates its total, bars, completed tasks and active members together. Surface colors are local consumer token overrides.
View and copy the complete example
import { Component, signal, computed } from '@angular/core';
import { NeuStatsCardComponent } from '@neural-ui/native/stats-card';
import { NeuToggleButtonGroupComponent } from '@neural-ui/native/toggle-button-group';
import { View, Text, ScrollView } from '@ng-native/components';
@Component({
selector: 'app-example',
imports: [NeuStatsCardComponent, NeuToggleButtonGroupComponent, View, Text, ScrollView],
template: `
<scroll-view class="product-scroll" keyboardShouldPersistTaps="handled" [showsVerticalScrollIndicator]="false"><view class="product-stack"><view class="product-section"><text class="product-title" accessibilityRole="header">Creative momentum</text><text class="product-caption">Neural Studio · Your week in perspective</text></view>
<neu-toggle-button-group label="Reporting period" [options]="periods" [value]="period()" (valueChange)="choosePeriod($event)" />
<view class="focus-metric"><neu-stats-card label="Focused hours" [value]="hours()" [change]="period()[0] === 'current' ? '+5.5 h compared with last week' : 'Your previous week'" description="Space for meaningful work" [svg]="trendIcon" tone="brand">
<view class="week-chart">
@for (day of week().days; track day.label) {
<view class="week-column" [accessible]="true" [accessibilityLabel]="day.label + ': ' + number.format(day.hours) + ' h'">
<text class="week-value">{{ number.format(day.hours) }}</text><view class="week-track"><view class="week-bar" [class.last-day]="$last" [style.height]="(day.hours * 8) + 'px'"></view></view><text class="week-day">{{ day.label.slice(0, 3) }}</text>
</view>
}
</view>
</neu-stats-card></view>
<view class="metric-pair"><view class="metric-small metric-mint"><neu-stats-card label="Completed tasks" [value]="week().tasks" description="Ideas delivered" [svg]="checkIcon" tone="success" /></view><view class="metric-small metric-lilac"><neu-stats-card label="Active members" [value]="week().members" description="People creating" [svg]="membersIcon" tone="brand" /></view></view>
<text class="product-caption">Illustrative studio data. Choose a week to compare the whole summary.</text></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); }
.product-stack { gap: 20px; }
.focus-metric { --neu-surface: #132e57; --neu-surface-border: #132e57; --neu-text: #f7faff; --neu-muted: #c6d8f0; --neu-metric-size: 40px; --neu-metric-line: 46px; }
.week-chart { flex-direction: row; gap: 12px; padding-top: 8px; }
.week-column { flex: 1; min-width: 0; gap: 8px; align-items: stretch; }
.week-value { color: #f7faff; text-align: center; font-size: 12px; }
.week-track { height: 64px; justify-content: flex-end; background-color: #244572; border-radius: 6px; overflow: hidden; }
.week-bar { background-color: #94ccff; border-radius: 6px; }
.week-bar.last-day { background-color: #ffbdad; }
.week-day { color: #c6d8f0; text-align: center; font-size: 12px; }
.metric-pair { flex-direction: row; align-items: stretch; gap: 12px; }
.metric-small { flex: 1; min-width: 0; --neu-metric-size: 28px; --neu-metric-line: 34px; }
.metric-mint { --neu-surface: #e3f0e9; --neu-surface-border: #e3f0e9; --neu-text: #183e32; --neu-muted: #426556; }
.metric-lilac { --neu-surface: #eee8f7; --neu-surface-border: #eee8f7; --neu-text: #3d2b5d; --neu-muted: #65537c; }
@media (max-width: 360px) { .metric-pair { flex-direction: column; } }
`,
})
export class ExampleComponent {
readonly metricLocale = 'en-US';
readonly number = new Intl.NumberFormat(this.metricLocale, { maximumFractionDigits: 1 });
readonly periods = [{ id: 'current', label: 'This week' }, { id: 'previous', label: 'Last week' }];
readonly period = signal<readonly string[]>(['current']);
choosePeriod(values: readonly string[]) { this.period.set(values.length ? values : [...this.period()]); }
readonly weeks = {
current: { tasks: 18, members: 6, days: [{ label: 'Monday', hours: 5 }, { label: 'Tuesday', hours: 6 }, { label: 'Wednesday', hours: 4 }, { label: 'Thursday', hours: 7 }, { label: 'Friday', hours: 4.5 }] },
previous: { tasks: 14, members: 5, days: [{ label: 'Monday', hours: 4 }, { label: 'Tuesday', hours: 5 }, { label: 'Wednesday', hours: 3 }, { label: 'Thursday', hours: 5 }, { label: 'Friday', hours: 4 }] },
};
readonly week = computed(() => this.period()[0] === 'previous' ? this.weeks.previous : this.weeks.current);
readonly hours = computed(() => this.number.format(this.week().days.reduce((sum, day) => sum + day.hours, 0)) + ' h');
readonly trendIcon = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><path d="m3 17 6-6 4 4 8-8M15 7h6v6"/></svg>';
readonly checkIcon = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><path d="m5 12 4 4L19 6"/></svg>';
readonly membersIcon = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="9" cy="8" r="3"/><path d="M3 21v-2a6 6 0 0 1 12 0v2M16 5a3 3 0 0 1 0 6M21 21v-2a6 6 0 0 0-4-5"/></svg>';
}Workspace overview
Present resolved work and available storage with contextual changes.
View and copy the complete example
import { Component } from '@angular/core';
import { NeuStatsCardComponent } from '@neural-ui/native/stats-card';
import { View, ScrollView } from '@ng-native/components';
@Component({
selector: 'app-example',
imports: [NeuStatsCardComponent, View, ScrollView],
template: `
<scroll-view class="usage-scroll" keyboardShouldPersistTaps="handled"><view class="usage-stack">
<neu-stats-card label="Resolved requests" value="128" change="+12 this week" description="Support workspace" [svg]="resolvedIcon" tone="success" />
<neu-stats-card label="Storage used" value="85%" change="15% available" description="Review attachments before the next release" [svg]="storageIcon" tone="warning" />
</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 resolvedIcon = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="m8 12 3 3 5-6"/><circle cx="12" cy="12" r="9"/></svg>';
readonly storageIcon = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="3"/><path d="M4 14h16M8 17h.01M12 17h.01"/></svg>';
}Change the settings and try the result.
Device captures shown in English.


Personalization
Projected content
After the statistic and its supporting text. Add a chart, trend or supporting action without replacing the built-in value.
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. |
| value | string | number | Required | Input | Value displayed by this presentation component, using the declared type. |
| change | string | '' | Input | Supporting change text for the statistic. The application calculates the change; the component displays it. |
| description | string | '' | Input | Supporting text. Individual components decide where this optional description is shown. |
| svg | string | '' | Input | Optional decorative SVG beside the metric heading. When empty, no icon container or reserved space is rendered. Use currentColor for the theme color. |
| tone | NeuTone | 'brand' | Input | Semantic color of the optional icon and its subtle background. The metric value and text remain unchanged. |
Models
This component declares no two-way models.
Outputs
This component declares no public outputs.
Types and data interfaces
Use the imports in your application. The definitions below are provided for reference.
NeuTone
import type { NeuTone } from '@neural-ui/native/foundation';
// Public definition for reference only. Import this type; do not redeclare it.
export type NeuTone = 'neutral' | 'brand' | 'accent' | 'success' | 'info' | 'warning' | 'danger';