A label over a large value, for dashboards and summary rows — with an optional prefix (a currency sign) and suffix (a unit) around the value.
registry/behivetech/atoms/stat at v0.4.5, snapshotted 2026-11-10
stat.tsx
1import { type HTMLAttributes } from "react";2import { getClassName } from "@behivetech/get-class-name";3import styles from "./stat.module.scss";45export interface StatProps extends Omit<6 HTMLAttributes<HTMLDivElement>,7 "prefix"8> {9 /** Descriptive label shown above the value */10 label: string;11 /** The primary metric to display */12 value: string | number;13 /** Optional prefix rendered before the value (e.g. "$") */14 prefix?: React.ReactNode;15 /** Optional suffix rendered after the value (e.g. "%", "ms") */16 suffix?: React.ReactNode;17 /** Additional class names to merge with the component root element */18 className?: string;19}2021export const Stat = ({22 label,23 value,24 prefix,25 suffix,26 className,27 ...rest28}: StatProps) => {29 const [rootClass, getChildClass] = getClassName({30 rootClass: "BHT__Stat",31 styles,32 className,33 });3435 return (36 <div {...rest} className={rootClass}>37 <span className={getChildClass("label")}>{label}</span>38 <div className={getChildClass("value-row")}>39 {prefix && <span className={getChildClass("prefix")}>{prefix}</span>}40 <span className={getChildClass("value")}>{value}</span>41 {suffix && <span className={getChildClass("suffix")}>{suffix}</span>}42 </div>43 </div>44 );45};
stat.module.scss
1// Material Design 3 type roles for a single metric: label-medium caption,2// headline-medium value, title-medium affixes.34.BHT__Stat {5 display: flex;6 flex-direction: column;7 gap: var(--spacing-2);89 &__label {10 font-family: var(--md-sys-typescale-label-medium-font, var(--font-body));11 font-size: var(--md-sys-typescale-label-medium-size, 0.75rem);12 font-weight: var(--md-sys-typescale-label-medium-weight, 500);13 line-height: var(--md-sys-typescale-label-medium-line-height, 1rem);14 letter-spacing: var(--md-sys-typescale-label-medium-tracking, 0.0417em);15 color: var(--md-sys-color-on-surface-variant, var(--color-text-muted));16 text-transform: uppercase;17 }1819 &__value-row {20 display: flex;21 align-items: baseline;22 gap: var(--spacing-1);23 }2425 &__value {26 font-family: var(27 --md-sys-typescale-headline-medium-font,28 var(--font-heading)29 );30 font-size: var(--md-sys-typescale-headline-medium-size, 1.75rem);31 font-weight: var(--md-sys-typescale-headline-medium-weight, 400);32 line-height: var(--md-sys-typescale-headline-medium-line-height, 2.25rem);33 letter-spacing: var(--md-sys-typescale-headline-medium-tracking, 0);34 color: var(--md-sys-color-on-surface, var(--color-text-heading));35 }3637 &__prefix,38 &__suffix {39 font-family: var(--md-sys-typescale-title-medium-font, var(--font-body));40 font-size: var(--md-sys-typescale-title-medium-size, 1rem);41 font-weight: var(--md-sys-typescale-title-medium-weight, 500);42 line-height: var(--md-sys-typescale-title-medium-line-height, 1.5rem);43 letter-spacing: var(--md-sys-typescale-title-medium-tracking, 0.0094em);44 color: var(--md-sys-color-on-surface-variant, var(--color-text-muted));45 }46}
index.ts
1export { Stat } from "./stat.js";2export type { StatProps } from "./stat.js";
stat.example.tsx
1import { Stat } from "./stat.js";23export const BasicStat = () => <Stat label="Total Pages" value={42} />;45export const StatWithPrefix = () => (6 <Stat label="Revenue" value={1200} prefix="$" />7);89export const StatWithSuffix = () => (10 <Stat label="Uptime" value={99.9} suffix="%" />11);1213export const StatWithPrefixAndSuffix = () => (14 <Stat label="Response Time" value={120} suffix="ms" />15);