Report sheet

Pro

The paged chassis of a report (release readiness, configuration audit): a cover with what it covers and when its data was read, numbered sections, an export bar, and a provenance footer saying who or what generated it from which sources. Prints one section per page.

Markdown

Preview

Install

With the Candor CLI

First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/report-sheet

Brings in: button, freshness-stamp, locale, utils · npm: lucide-react@^1.67.0

Usage

TSX · The example above
"use client"

import { ReportSection, ReportSheet } from "@/components/report-sheet"
import { ComparisonView } from "@/components/comparison-view"
import { KpiRow } from "@/components/stat-card"

const ago = (hours: number) => new Date(Date.now() - hours * 3_600_000).toISOString()

export default function Example() {
  return (
    <ReportSheet
      className="max-w-3xl"
      title="Release readiness: 4.2"
      scope="Acme Production"
      period="Changes since the 4.1 release"
      generatedAt={ago(0)}
      generatedBy="Keel"
      dataReadAt={ago(3)}
      onExport={() => {}}
    >
      <ReportSection number={1} title="Summary" lede="From last night’s CI run and the 4.1 release.">
        <KpiRow
          kpis={[
            { label: "Changes in the release", value: 62, delta: { value: 18, vs: "4.1 release", good: "down" } },
            { label: "Failing tests", value: 6, delta: { value: -4, vs: "last week", good: "down" } },
            { label: "Users affected", value: null, missing: "Needs session analytics, which isn’t connected." },
          ]}
        />
      </ReportSection>
      <ReportSection number={2} title="Before and after" lede="This release against 4.1.">
        <ComparisonView
          before="4.1"
          after="4.2"
          rows={[
            { label: "Test coverage", before: 0.72, after: 0.78, format: "percent", good: "up" },
            { label: "Failing tests", before: 10, after: 6, good: "down" },
          ]}
        />
      </ReportSection>
    </ReportSheet>
  )
}

<ReportSheet>

PropTypeDefaultDescription
titlerequiredstring—The report's name, as the cover heading.
scoperequiredstring—e.g. "Shop production".
periodstring | undefined—The time span the report covers, shown after the scope, e.g. "March 2026".
generatedAtrequiredstring—When the report was generated (ISO timestamp), shown in the footer.
generatedByrequiredstring—Who or what generated it, a person or an agent, named in the footer.
dataReadAtrequiredstring | null—When the underlying data was read (ISO timestamp); null shows that it's unknown.
onExport((format: "pdf" | "csv" | "md") => void) | undefined—Shows PDF, CSV and Markdown export buttons; called with the chosen format.
childrenrequiredReact.ReactNode—What goes inside.
classNamestring | undefined—Extra classes for the outer element.

<ReportSection>

A numbered section with one prop shape: number, title, optional lede, content.

PropTypeDefaultDescription
numberrequirednumber—The section's number, shown zero-padded above the title.
titlerequiredstring—The section heading.
ledestring | undefined—A sentence under the heading saying what the section shows.
childrenrequiredReact.ReactNode—What goes inside.
classNamestring | undefined—Extra classes for the outer element.

Strings

The fixed words, in English by default. Change any of them under reportSheet in <LocaleProvider strings={{ … }}>; the table is exported as reportSheetStrings.

KeyEnglish
reportReport
dataReadData read
pdfPDF
csvCSV
mdMarkdown
footerGenerated by {by} on {date}. Figures come from the sources named in each section; a dash means it wasn’t measured.