Skip to contentVibraUI
Metrics

Explain number

A popover that shows where a number came from: the source, the formula, and the rows it was computed from.

Takes the provenance half of a traced() result. The trigger is a plain button with an accessible name, so the popover opens with Enter or Space and closes on Escape like any other. Column headings are written from the row keys — "sessionSeconds" heads a column as "Session seconds", an acronym like MRR is left alone — and numeric columns are right-aligned on a fixed advance. It admits to sampling: "Showing 8 of 30" appears whenever fewer rows are on show than the number was computed from. Compute with traced on the server and pass the provenance down; only the kept rows travel.

Install

npx shadcn@latest add @vibra/explain-number

Needs the @vibra registry in your components.json — set it up once.

Examples

Props

PropTypeDefaultDescription
provenanceProvenance—Where the number came from — the provenance half of a traced() result.
valueReact.ReactNode—The number itself, already formatted, shown at the top of the popover.
triggerLabelstring"Explain this number"The trigger button's accessible name.
side"top" | "right" | "bottom" | "left""bottom"Which side of the trigger the popover opens on.
align"start" | "center" | "end""start"How the popover lines up against the trigger.

Dependencies

Source

components/ui/explain-number.tsx
"use client"

import * as React from "react"
import { SigmaIcon } from "lucide-react"

import { cn } from "@/lib/utils"
import { formatNumber } from "@/lib/format"
import { isSampled, type Provenance, type ProvenanceValue } from "@/lib/metric"
import { Button } from "@/components/ui/button"
import {
  Popover,
  PopoverContent,
  PopoverHeader,
  PopoverTitle,
  PopoverTrigger,
} from "@/components/ui/popover"
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table"

// A key is written the way a heading is: acronyms kept (MRR), camelCase and
// snake_case split into words, and only the first one capitalised — so
// "sessionSeconds" heads a column as "Session seconds", not "Session Seconds".
/** Writes a row key as a column heading. */
export function columnLabel(key: string): string {
  const words = key
    .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
    .replace(/[_-]+/g, " ")
    .split(/\s+/)
    .filter(Boolean)
    .map((word) => (word === word.toUpperCase() ? word : word.toLowerCase()))

  const [first = "", ...rest] = words
  return [first.charAt(0).toUpperCase() + first.slice(1), ...rest].join(" ")
}

/** Numbers are right-aligned on a fixed advance; everything else reads left. */
function isNumeric(value: ProvenanceValue): boolean {
  return typeof value === "number"
}

function cellText(value: ProvenanceValue): string {
  if (value === null || value === undefined) return "—"
  if (typeof value === "number") return formatNumber(value)
  if (typeof value === "boolean") return value ? "yes" : "no"
  return value
}

// The trigger button is the root: className and the rest of the props land on
// it, the way DatePicker's does.
export type ExplainNumberProps = Omit<
  React.ComponentProps<typeof Button>,
  "value" | "children" | "render" | "variant" | "size"
> & {
  /** Where the number came from — the output of `traced`. */
  provenance: Provenance
  /** The number itself, already formatted, shown at the top of the popover. */
  value?: React.ReactNode
  /** The trigger's accessible name. */
  triggerLabel?: string
  side?: React.ComponentProps<typeof PopoverContent>["side"]
  align?: React.ComponentProps<typeof PopoverContent>["align"]
}

/**
 * The rows a number was computed from, in a popover: how many there were, where
 * they came from, the formula, and the first few rows themselves. A dashboard
 * figure that a reader cannot check is a figure they have to trust; this is the
 * check.
 */
function ExplainNumber({
  className,
  provenance,
  value,
  triggerLabel = "Explain this number",
  side = "bottom",
  align = "start",
  ...props
}: ExplainNumberProps) {
  const { source, formula, columns, rows, total } = provenance
  const showTable = columns.length > 0 && rows.length > 0

  return (
    <Popover>
      <PopoverTrigger
        render={
          <Button
            type="button"
            data-slot="explain-number"
            variant="ghost"
            size="icon-xs"
            aria-label={triggerLabel}
            className={cn("text-muted-foreground", className)}
            {...props}
          >
            <SigmaIcon aria-hidden="true" />
          </Button>
        }
      />

      <PopoverContent
        side={side}
        align={align}
        className="w-[min(22rem,calc(100vw-2rem))] gap-2 p-3"
      >
        <PopoverHeader>
          <PopoverTitle>How this number is computed</PopoverTitle>
        </PopoverHeader>

        {value !== undefined ? (
          <div
            data-slot="explain-number-value"
            className="text-xl font-semibold tracking-tight tabular-nums"
          >
            {value}
          </div>
        ) : null}

        <p data-slot="explain-number-source" className="text-xs text-muted-foreground">
          {`${formatNumber(total, { maximumFractionDigits: 0 })} ${total === 1 ? "row" : "rows"} from ${source}`}
        </p>

        <code
          data-slot="explain-number-formula"
          className="rounded-md bg-muted px-2 py-1 font-mono text-xs break-words text-foreground"
        >
          {formula}
        </code>

        {showTable ? (
          <Table
            data-slot="explain-number-rows"
            className="text-xs [&_td]:px-2 [&_td]:py-1 [&_th]:h-7 [&_th]:px-2"
          >
            <TableHeader>
              <TableRow>
                {columns.map((column) => (
                  <TableHead
                    key={column}
                    className={cn(
                      "text-xs font-medium whitespace-nowrap",
                      isNumeric(rows[0]?.[column]) && "text-end"
                    )}
                  >
                    {columnLabel(column)}
                  </TableHead>
                ))}
              </TableRow>
            </TableHeader>
            <TableBody>
              {rows.map((row, index) => (
                <TableRow key={index}>
                  {columns.map((column) => (
                    <TableCell
                      key={column}
                      className={cn(
                        "whitespace-nowrap",
                        isNumeric(row[column]) ? "text-end tabular-nums" : "text-muted-foreground"
                      )}
                    >
                      {cellText(row[column])}
                    </TableCell>
                  ))}
                </TableRow>
              ))}
            </TableBody>
          </Table>
        ) : null}

        {isSampled(provenance) ? (
          <p data-slot="explain-number-sample" className="text-xs text-muted-foreground">
            {`Showing ${formatNumber(rows.length, { maximumFractionDigits: 0 })} of ${formatNumber(total, { maximumFractionDigits: 0 })}`}
          </p>
        ) : null}
      </PopoverContent>
    </Popover>
  )
}

export { ExplainNumber }