Dashboard tile
ProA dashboard tile: a title, when its data was read, the state of that data, and a chart, a stat or a table. Loading, empty, partial and error look as they do in ChartFrame; partial shows what exists and says what's missing. A chart inside keeps its title for assistive tech only and draws no frame of its own, so the tile's title isn't said twice. The drill-down is a button whose words say what it filters ("Show the 12 failed runs"); the view switch (drawn with onViewChange) offers the views the app passes, and a view the data doesn't allow can stay, locked, saying why.
Unknown stays unknown: without readAt there's no stamp at all, and readAt={null} says "Never read".
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/dashboard-tile
Brings in: button, chart-frame, data, freshness-stamp, heading-level, heading-scope, locale, toggle-group, tokens, utils · npm: lucide-react@^1.67.0
Usage
"use client"
import * as React from "react"
import { BarChart } from "@/components/candor/bar-chart"
import { LineChart } from "@/components/candor/line-chart"
import { DashboardTile } from "@/components/candor/dashboard-tile"
import { useAllowedViews } from "@/components/candor/chart-views"
import type { Series } from "@/lib/candor/data"
const days = ["Mon", "Tue", "Wed", "Thu", "Fri"]
const runs: Series[] = [{ id: "failed", label: "Failed", values: [2, 4, 1, null, 5] }]
export default function Example() {
const [view, setView] = React.useState("bar")
const allowed = useAllowedViews({ categories: days.length, series: runs.length, ordered: true, partsOfWhole: false, negative: false })
const views = allowed.filter((v) => ["bar", "line", "donut"].includes(v.view)).map((v) => ({ value: v.view, label: v.label, locked: v.reason }))
const [readAt] = React.useState(() => new Date(Date.now() - 40 * 60 * 1000).toISOString())
return (
<DashboardTile
className="max-w-xl"
title="Failed runs"
subtitle="Production · this week"
readAt={readAt}
everyHours={1}
state={{ kind: "partial", note: "Thursday's runs haven't been read yet." }}
views={views}
view={view}
onViewChange={setView}
drill={{ label: "Show the 12 failed runs", onDrill: () => {} }}
>
{view === "line" ? <LineChart title="Failed runs" x={days} series={runs} height={160} /> : <BarChart title="Failed runs" categories={days} series={runs} height={160} />}
</DashboardTile>
)
}<DashboardTile>
| Prop | Type | Default | Description |
|---|---|---|---|
| titlerequired | string | — | What the tile shows, as its heading. |
| subtitle | string | undefined | — | A line under the title: the period, the unit, the scope. |
| readAt | string | null | undefined | — | When the data was read (ISO date), shown as a freshness stamp; `null` says "Never read". Left out, no stamp. |
| everyHours | number | undefined | — | How often, in hours, the data should be read again; the stamp says overdue once the data is older than 1.5 times it. |
| state | ChartState | undefined | { kind: "ready" } | Loading, empty (with why), partial (with what's missing) or error (with why). Defaults to ready. |
| onRetry | (() => void) | undefined | — | Shows Try again under an error; called when it's pressed. Pass it only when it loads the data again. |
| drill | { label: string; onDrill: () => void } | undefined | — | A drill-down: a button whose `label` says what it filters ("Show the 12 failed runs"), and what it does. |
| views | DashboardTileView[] | undefined | — | The views to switch between; pass the ones `allowedViews` allows, or lock the others with their reason. The switch is drawn only with more than one view and an `onViewChange`. |
| view | string | undefined | — | The view shown now, one of `views`' values. |
| onViewChange | ((view: string) => void) | undefined | — | Called with the view the person picks. Without it, there's no view switch. |
| toolbar | React.ReactNode | undefined | — | Actions at the tile's top corner: an `ArtifactToolbar`, say. |
| headingLevel | HeadingLevel | undefined | — | The heading's level, to fit the page's outline. Defaults to one below the nearest `HeadingScope`, else 2 (`<h2>`). |
| children | React.ReactNode | undefined | — | The content: a chart, a stat or a table. Shown while ready or partial, in a `HeadingScope` under the tile's title, so a Candor item in it draws its heading one level below. |
| className | string | undefined | — | Classes for the root, merged with Candor's. |
Strings
The fixed words, in English by default. Change any of them under dashboardTile in <LocaleProvider strings={{ … }}>; the table is exported as dashboardTileStrings.
| Key | English |
|---|---|
| views | View |
Types
- DashboardTileView
- One view the tile can switch to: its value and its words; `locked` says why it can't be chosen for this data.
{ /** The value `onViewChange` is called with. */ value: string; /** The view's words: "Bars", "Table". */ label: string; /** Why this view can't show this data (from `allowedViews`' `reason`). It stays in the list, saying why. `null` or left out: unlocked. */ locked?: string | null | undefined; }
Types from other items
The props above take these. Each is defined by another item; import it from the path shown.
- ChartState from @/lib/candor/data
{ kind: "ready"; } | { kind: "loading"; } /** Nothing to plot, and why. */ | { kind: "empty"; reason: string; } /** Some of the range is missing. */ | { kind: "partial"; note: string; } | { kind: "error"; reason: string; }- 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