Stats

The <smart-stats> component renders a list of statistic cards (label/value pairs with optional previous value, change indicator, trend, icon, and action slot). It follows the Base + Standard + Wrapper pattern with an InjectionToken-based extension mechanism. The abstract StatsBaseComponent defines the shared API — optional IStatsOptions and cssClass (alias class). StatsStandardComponent is a barebones placeholder concrete implementation. StatsComponent is the public wrapper that renders StatsStandardComponent by default and accepts a custom replacement via STATS_STANDARD_COMPONENT_TOKEN.


Usage

<smart-stats [options]="options" />

Components

StatsComponent (<smart-stats>)

Main wrapper component. Renders StatsStandardComponent by default. When STATS_STANDARD_COMPONENT_TOKEN is provided, renders the injected component via NgComponentOutlet.

StatsStandardComponent (<smart-stats-standard>)

Barebones placeholder concrete implementation. Renders a wrapper <div> containing an optional <h3 class="title"> and a <dl> with one <div class="item"> per item. Each item renders an optional icon (iconTpl in <div class="icon">), label (<dt class="label">), value (<dd class="value">), optional previous value (<dd class="previous">), optional change with data-trend attribute (<dd class="change">), and optional action template (actionTpl in <div class="action">). The external cssClass is applied to the root wrapper. It does not include any visual styling — it exists solely as the default structural placeholder until a custom implementation is registered through the token.

StatsPresetComponent (<smart-stats-preset>)

Styled variation that extends StatsBaseComponent and is a drop-in replacement for StatsStandardComponent. Register it via STATS_STANDARD_COMPONENT_TOKEN to restyle every <smart-stats>, or use the <smart-stats-preset> selector directly. Renders the Preline "Three-Column Stats with Primary Accent" look: a responsive grid of stat blocks, each with an optional leading icon (iconTpl), a label heading, the big primary-accent value (with an optional inline change badge coloured by trend — green for up, red for down, gray for neutral/unset), an optional muted previousValue sub-line, and an optional actionTpl. Column count comes from options.columns (default 3); an optional options.title renders as a heading above the grid. All classes are smart:-prefixed Tailwind with explicit dark: variants. The class recipes live in preset/preset-classes.util.ts (getStatsContainerClasses, getStatsGridClasses, getStatsChangeClasses, etc.).

Because StatsComponent renders injected components via NgComponentOutlet (which passes inputs by canonical name), StatsPresetComponent overrides cssClass as input<string>('') without the class alias. Bind it as [cssClass] when using the <smart-stats-preset> selector directly, or just pass class on <smart-stats> (the wrapper forwards it).

StatsBaseComponent (abstract)

Abstract base directive for extending custom stats implementations. Exposes options as an InputSignal<IStatsOptions | undefined> and cssClass as an InputSignal<string> (with alias class).

API

Inputs

InputTypeDefaultDescription
optionsInputSignal<IStatsOptions | undefined>-Optional configuration (title, items, columns)
classInputSignal<string>''External CSS classes (alias for cssClass)

IStatsOptions

items is required. The default StatsStandardComponent consumes every property; a section is rendered only when its template/string is provided. The trend value is exposed via the data-trend attribute on <dd class="change"> for downstream styling. columns is a hint for custom implementations to lay out the grid; the default placeholder ignores it.

STATS_STANDARD_COMPONENT_TOKEN

InjectionToken that allows replacing the default StatsStandardComponent with a custom implementation. Provide a Type<StatsBaseComponent> to override.

Extending the base class

import {
  ChangeDetectionStrategy,
  Component,
  computed,
  input,
  ViewEncapsulation,
} from '@angular/core';

import {
  IStatsOptions,
  STATS_STANDARD_COMPONENT_TOKEN,
  StatsBaseComponent,
  StatsComponent,
} from '@smartsoft001/angular';

@Component({
  selector: 'docs-custom-stats',
  template: `
    <div [class]="containerClasses()" [attr.data-columns]="columns()">
      @if (options()?.title) {
        <h3 class="docs-stats__title">{{ options()!.title }}</h3>
      }

      <dl class="docs-stats__grid">
        @for (item of options()?.items ?? []; track $index) {
          <div
            class="docs-stats__item"
            [attr.aria-label]="item.ariaLabel ?? null"
          >
            <dt class="docs-stats__label">{{ item.label }}</dt>
            <dd class="docs-stats__value">{{ item.value }}</dd>
            @if (
              item.previousValue !== undefined && item.previousValue !== null
            ) {
              <dd class="docs-stats__previous">{{ item.previousValue }}</dd>
            }
            @if (item.change) {
              <dd
                class="docs-stats__change"
                [attr.data-trend]="item.trend ?? null"
              >
                {{ item.change }}
              </dd>
            }
          </div>
        }
      </dl>
    </div>
  `,
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomStatsComponent extends StatsBaseComponent {
  // NgComponentOutlet passes 'cssClass' by canonical name, not the 'class' alias.
  override cssClass = input<string>('');

  columns = computed(() => this.options()?.columns ?? 3);

  containerClasses = computed(() =>
    ['docs-stats', this.cssClass()].filter(Boolean).join(' '),
  );
}

@Component({
  selector: 'docs-stats-custom-example',
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [StatsComponent],
  // The token swaps the standard stats for the custom one everywhere below this
  // component, so consumers keep writing `<smart-stats>`.
  providers: [
    {
      provide: STATS_STANDARD_COMPONENT_TOKEN,
      useValue: CustomStatsComponent,
    },
  ],
  template: `<smart-stats [options]="options" />`,
})
export class StatsCustomExampleComponent {
  options: IStatsOptions = {
    title: 'By the numbers',
    columns: 3,
    items: [
      {
        label: 'Accuracy rate',
        value: '99.95%',
        previousValue: 'in fulfilling orders',
        change: '+0.4% this quarter',
        trend: 'up',
      },
      {
        label: 'Startup businesses',
        value: '2,000+',
        previousValue: 'partner with us',
      },
      {
        label: 'Happy customers',
        value: '85%',
        previousValue: 'this year alone',
      },
    ],
  };
}

Source

The component lives in packages/shared/angular/src/lib/components/stats and is documented for Claude Code by the angular-components-stats skill.