Skip to main content
astrocraft-ui/ components · 101

Stat

Free · MIT

Headless, accessible, and styled entirely through the attribute surface below — bring your own CSS system, or start from the reference theme.

Install

Without a flag you get no styling at all — plain HTML carrying the attribute surface below. --theme copies the same theme in two dialects;--bridge lumos re-points either one onto Lumos for Astro's tokens (it needs a theme to re-point, and Lumos itself, already in your project).

Unstyled — behavior only, you write the CSS

Install command
npx astrocraft-ui add display/stat

Plain-CSS theme — no build step

Install command
npx astrocraft-ui add display/stat --theme css

Tailwind theme — needs Tailwind v4

Install command
npx astrocraft-ui add display/stat --theme tailwind

Plain-CSS theme, re-pointed onto Lumos tokens

Install command
npx astrocraft-ui add display/stat --theme css --bridge lumos

Tailwind theme, re-pointed onto Lumos tokens

Install command
npx astrocraft-ui add display/stat --theme tailwind --bridge lumos

Live demo

Stat

A KPI row is a description list, which is why "Revenue" and the number under it are associated rather than merely adjacent. Each delta announces its direction as a WORD — green-up / red-down is the canonical "colour as the only carrier of meaning" failure.

Revenue
£12,480Increased 12.4%
Churn
2.1%Decreased 0.4pp
Seats
318No change 0

Attribute surface

With no class-merging machinery, these attributes are the whole extension point. State is a data-attribute or a native attribute; visibility is the hiddenattribute. Generated from source by pnpm slots.

ComponentSlotsVariantsRuntime stateNative state
`Stat.astro``stat`———
`StatDelta.astro``stat-delta` `stat-delta-direction``data-trend`: `up` · `down` · `flat`——
`StatGroup.astro``stat-group``data-columns`: `1` · `2` · `3` · `4`——
`StatLabel.astro``stat-label`———
`StatValue.astro``stat-value`———

Source

What the command copies — 6 files, alias-free so the copy lands standing alone. This is the whole component, shown without its comments; the files you install keep them, with the reasoning behind every rule.

src/components/ui/display/stat/Stat.astro
---
import type { HTMLAttributes } from "astro/types";

type Props = HTMLAttributes<"div">;

const { class: className, ...rest } = Astro.props;
---

<div class={className} data-slot="stat" {...rest}><slot /></div>
src/components/ui/display/stat/StatDelta.astro
---
import type { HTMLAttributes } from "astro/types";

type Props = HTMLAttributes<"span"> & {
  trend?: "up" | "down" | "flat";
  label?: string;
};

const { trend = "flat", label, class: className, ...rest } = Astro.props;

const WORD = { up: "Increased", down: "Decreased", flat: "No change" } as const;
const direction = `${label ?? WORD[trend]} `;
---

<span class={className} data-slot="stat-delta" data-trend={trend} {...rest}>
  <span data-slot="stat-delta-direction">{direction}</span><slot />
</span>
src/components/ui/display/stat/StatGroup.astro
---
import type { HTMLAttributes } from "astro/types";

type Props = HTMLAttributes<"dl"> & { columns?: 1 | 2 | 3 | 4 };

const { columns = 3, class: className, ...rest } = Astro.props;
---

<dl class={className} data-slot="stat-group" data-columns={columns} {...rest}>
  <slot />
</dl>
src/components/ui/display/stat/StatLabel.astro
---
import type { HTMLAttributes } from "astro/types";

type Props = HTMLAttributes<"dt">;

const { class: className, ...rest } = Astro.props;
---

<dt class={className} data-slot="stat-label" {...rest}><slot /></dt>
src/components/ui/display/stat/StatValue.astro
---
import type { HTMLAttributes } from "astro/types";

type Props = HTMLAttributes<"dd">;

const { class: className, ...rest } = Astro.props;
---

<dd class={className} data-slot="stat-value" {...rest}><slot /></dd>
src/components/ui/display/stat/index.ts
import Stat from "./Stat.astro";
import StatDelta from "./StatDelta.astro";
import StatGroup from "./StatGroup.astro";
import StatLabel from "./StatLabel.astro";
import StatValue from "./StatValue.astro";

export { Stat, StatDelta, StatGroup, StatLabel, StatValue };
export default StatGroup;

What you get

The component source, copied into your project by npx astrocraft-ui add display/stat — no package dependency, no CSS to fight. Whatever the paid blocks compose, this is it.