Skip to content
← Blocks

Metrics Strip

A complete metrics strip section, ready to adapt to your product.

Open ↗

Make it yours.

Install the editable source and its dependencies into your React + Tailwind project.

Scroll horizontally for long lines
pnpm dlx shadcn@4.0.8 add http://localhost:3000/r/metrics-strip.json

Use it

Scroll horizontally for long lines
"use client";
import { MetricsStrip } from "@/components/jez-ui/blocks/metrics-strip";

export default function Example() {
  return (
    <>
      <MetricsStrip />
    </>
  );
}

Compose your own

These styled parts are included in the same install. Use children to build your layout; add className only when you want an override.

Scroll horizontally for long lines
"use client";
import {
  MetricsStrip,
  MetricsStripItem,
  MetricsStripLabel,
  MetricsStripValue,
} from "@/components/jez-ui/blocks/metrics-strip";
export default function Example() {
  return (
    <MetricsStrip>
      <MetricsStripItem>
        <MetricsStripLabel>Projects shipped</MetricsStripLabel>
        <MetricsStripValue>42</MetricsStripValue>
      </MetricsStripItem>
      <MetricsStripItem>
        <MetricsStripLabel>Team members</MetricsStripLabel>
        <MetricsStripValue>12</MetricsStripValue>
      </MetricsStripItem>
    </MetricsStrip>
  );
}
Scroll horizontally for long lines
import { MetricsStrip, MetricsStripItems, MetricsStripLabel, MetricsStripValue, MetricsStripItem } from "@/components/jez-ui/blocks/metrics-strip";
Read the composition guide →

Props & types

Scroll horizontally for long lines
export type MetricsStripOptions = {
  items?: { label: string; value: string }[];
  className?: string;
};

export type MetricsStripProps = Omit<
  React.ComponentProps<"dl">,
  keyof MetricsStripOptions
> &
  MetricsStripOptions;

MetricsStripProps

Source

View 2 source files

registry/blocks/metrics-strip.tsx

Scroll horizontally for long lines
"use client";
import * as React from "react";
import { cn } from "../ui/utils";
export type MetricsStripOptions = {
  items?: { label: string; value: string }[];
  className?: string;
};
export type MetricsStripProps = Omit<
  React.ComponentProps<"dl">,
  keyof MetricsStripOptions
> &
  MetricsStripOptions;
function useMetricsStripModel({
  items = [
    { label: "Projects in this demo", value: "12" },
    { label: "Open tasks", value: "38" },
    { label: "Teammates", value: "6" },
  ],
  className,
  children,
  ...rootProps
}: MetricsStripProps) {
  return { items, className, children, rootProps };
}
const MetricsStripCompositionContext = React.createContext<ReturnType<
  typeof useMetricsStripModel
> | null>(null);
function useMetricsStripComposition() {
  const context = React.useContext(MetricsStripCompositionContext);
  if (!context)
    throw new Error("MetricsStrip parts must be inside MetricsStrip.");
  return context;
}
export function MetricsStrip(props: MetricsStripProps) {
  const model = useMetricsStripModel(props);
  const { className, rootProps, children } = model;
  return (
    <MetricsStripCompositionContext.Provider value={model}>
      <dl
        {...rootProps}
        className={cn(
          "grid gap-6 border-y border-border py-7 sm:grid-cols-3",
          className,
        )}
      >
        {children !== undefined ? children : <MetricsStripItems />}
      </dl>
    </MetricsStripCompositionContext.Provider>
  );
}

export function MetricsStripItems({ children }: React.PropsWithChildren) {
  const { items } = useMetricsStripComposition();
  return children === undefined
    ? items.map((i) => (
        <MetricsStripItem key={i.label}>
          <MetricsStripLabel>{i.label}</MetricsStripLabel>
          <MetricsStripValue>{i.value}</MetricsStripValue>
        </MetricsStripItem>
      ))
    : children;
}

export function MetricsStripLabel({
  className,
  ...props
}: React.ComponentProps<"dt">) {
  return (
    <dt
      data-slot="metrics-strip-label"
      className={cn("text-sm text-muted-foreground", className)}
      {...props}
    />
  );
}
export function MetricsStripValue({
  className,
  ...props
}: React.ComponentProps<"dd">) {
  return (
    <dd
      data-slot="metrics-strip-value"
      className={cn("mt-2 font-display text-3xl tabular-nums", className)}
      {...props}
    />
  );
}

export function MetricsStripItem(props: React.ComponentProps<"div">) {
  return <div data-slot="metrics-strip-item" {...props} />;
}

registry/ui/utils.ts

Scroll horizontally for long lines
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...values: ClassValue[]) {
  return twMerge(clsx(values));
}

Dependencies

clsx@2.1.1 · tailwind-merge@3.5.0

Accessibility & behaviour

Provide meaningful labels and preserve keyboard focus styles. Check contrast when customising theme colours.

Read the accessibility and performance guide →