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

Import

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

Change the settings and try the result.

Device captures shown in English.

Stats Card · android · native capture
AndroidNative screenshot
Stats Card · ios · native capture
iOSNative screenshot

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

NameTypeDefaultBindingDescription
labelstringRequiredInputHuman-readable name for the control, action or group.
valuestring | numberRequiredInputValue displayed by this presentation component, using the declared type.
changestring''InputSupporting change text for the statistic. The application calculates the change; the component displays it.
descriptionstring''InputSupporting text. Individual components decide where this optional description is shown.
svgstring''InputOptional decorative SVG beside the metric heading. When empty, no icon container or reserved space is rendered. Use currentColor for the theme color.
toneNeuTone'brand'InputSemantic 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

NeuTone.ts
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';