Narrative block
ProReport prose as claims, each followed by what it rests on: a source as a Citation marker, a section of the report as a mark that opens it. A claim that states a figure and gives no evidence is never shown as plain fact: it is muted, underlined with a dashed line and followed by "No evidence given for this figure". A claim with no figure and no evidence reads as ordinary prose. The claims are model output, drawn as text.
Version 5.2.0· other versions
This page is for 5.2.0, the current release. An earlier release’s page is the Markdown that release published, so the docs match the version you have installed (candor-lock.json records it).
Not in the docs of 1.3.0, 1.4.0, 1.5.0, 1.5.1, 1.6.0, 1.7.0, 1.8.0, 1.8.1, 1.9.0, 1.9.1, 2.0.0, 2.1.0, 2.2.0, 2.3.0, 2.4.0, 2.5.0, 2.5.1, 2.6.0, 2.6.1, 2.6.2, 2.7.0, 2.8.0, 2.9.0, 2.10.0, 3.0.0, 4.0.0, 4.0.1, 4.0.2 and 4.1.0: the page came later, or had another name then.
Docs pages weren’t kept for 1.0.0, 1.0.1, 1.1.0, 1.1.1, 1.2.0 and 1.2.1: they are kept from 1.3.0 on, and before that only llms.txt was published.
Preview
Loading the preview
Install
First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/narrative-block
Brings in: bidi, chat, citation, heading-level, heading-scope, locale, tokens, utils · npm: lucide-react@^1.67.0
Usage
"use client"
import { NarrativeBlock } from "@/components/candor/narrative-block"
// The second claim states a figure with nothing behind it, so it is shown as unsupported rather than as fact.
export default function Example() {
return (
<NarrativeBlock
className="max-w-xl"
heading="Summary"
onOpenSection={() => {}}
claims={[
{
id: "growth",
text: "Pipeline grew 12% against last quarter, mostly in the mid-market segment.",
evidence: [{ id: "q1", marker: 1, kind: "query", label: "Pipeline by segment", origin: "Query on opportunities" }, { section: 2, title: "Pipeline" }],
},
{ id: "win", text: "Win rate fell to 18%." },
{ id: "q3", text: "Q3 deals are concentrated in late stages.", numeric: false, evidence: [{ section: 3, title: "Stages" }] },
]}
/>
)
}<NarrativeBlock>
| Prop | Type | Default | Description |
|---|---|---|---|
| claimsrequired | NarrativeClaim[] | — | The prose, as claims in reading order. |
| onOpenSection | ((number: number) => void) | undefined | — | Opens a section of the report by its number. Without it a section is named but isn't a button. |
| heading | string | undefined | — | A heading over the prose, "Summary". |
| headingLevel | HeadingLevel | undefined | — | The heading's level in the page's outline. Defaults to one below the nearest `HeadingScope`, else 2 (`<h2>`). |
| className | string | undefined | — | Classes for the outer box. |
Functions
claimStatesNumber(text: string)Whether text holds a decimal digit in any script (3, ٣, ३): a claim that does states a figure.
Strings
The fixed words, in English by default. Change any of them under narrativeBlock in <LocaleProvider strings={{ … }}>; the table is exported as narrativeBlockStrings.
| Key | English |
|---|---|
| unsupported | No evidence given for this figure |
| sectionMarker | §{number} |
| sectionLabel | Section {number}: {title} |
Motion
| Moment | Family | What it does |
|---|---|---|
| tint | tint | A section mark's border and text colour change when the pointer is over it, and a ring fades in when it takes keyboard focus. |
Set with --cd-motion-narrative-block-<moment>-* in your brand file; the families are in the design reference.
Types
- NarrativeSection
- A section of the report a claim rests on, opened through `onOpenSection`.
{ /** The section's number, as `ReportSection` shows it. */ section: number; /** The section's title. */ title: string; }- NarrativeEvidence
- What a claim rests on: a source (the free `Citation`'s shape, a document, a query, a web page) or a section of the report.
MessageSource | NarrativeSection- NarrativeClaim
- One claim in the prose and what it rests on.
{ /** Stable across renders. */ id: string; /** The claim's words, from the model: drawn as text. */ text: string; /** The sources and sections the claim rests on. A claim that states a figure and has none is shown as unsupported. */ evidence?: NarrativeEvidence[] | undefined; /** * Whether the claim states a figure. Left out, a claim states one when its text holds a digit (in any script). Set it * `false` for digits that aren't a figure ("Q3", a year) and `true` for a figure in words ("twelve accounts"). */ numeric?: boolean | undefined; }
Types from other items
The props above take these. Each is defined by another item; import it from the path shown.
- HeadingLevel from @/lib/candor/heading-level
- A heading's level in the page's outline: `1` is `<h1>`, `6` is `<h6>`. Every Candor item that draws a heading takes its `headingLevel` as this type; the level is where the heading sits in the outline, never how large it looks.
1 | 2 | 3 | 4 | 5 | 6- MessageSource from @/lib/candor/chat
{ id: string; /** The [n] shown inline. Assigned by the service, so it is stable across renders. */ marker: number; kind: SourceKind; label: string; /** An inert excerpt shown in the popover. Text only. */ snippet?: string | undefined; /** Where it came from in a human sense: "Docs · Sales process v3", "Query on orders". */ origin?: string | undefined; provisional?: boolean | undefined; }- SourceKind from @/lib/candor/chat
- "document", "web", "query", "code", "data", "workflow", "knowledge", or the app's own; unknown kinds read as "Source".
string