Artifact toolbar
ProThe actions on an artifact or a dashboard tile: maximise and restore, download (one format a button, several a menu), and "Ask about this", which hands the artifact to the app's chat (Candor attaches nothing itself). Each button names the artifact, so a page of tiles doesn't read "Download, Download, Download". A control whose handler isn't given isn't drawn; one that can't be used now stays, locked, saying why. It is one tab stop: the arrow keys move between its buttons (ArtifactToolbarButton for your own).
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/artifact-toolbar
Brings in: button, dropdown-menu, locale, locked, tokens, utils · npm: @base-ui/react@^1.9.0, lucide-react@^1.67.0
Usage
"use client"
import * as React from "react"
import { Share2 } from "lucide-react"
import { ArtifactToolbar, ArtifactToolbarButton } from "@/components/candor/artifact-toolbar"
import { TooltipProvider } from "@/components/candor/ui/tooltip"
export default function Example() {
const [maximised, setMaximised] = React.useState(false)
const [last, setLast] = React.useState("Nothing yet.")
return (
<TooltipProvider>
<div className="flex max-w-md flex-col gap-2 rounded-xl border bg-card p-4">
<div className="flex items-center gap-2">
<p className="flex-1 text-sm font-semibold">Failed runs this week</p>
<ArtifactToolbar
title="Failed runs this week"
maximised={maximised}
onMaximisedChange={setMaximised}
downloads={[{ format: "csv", label: "CSV" }, { format: "png", label: "PNG image" }]}
onDownload={(format) => setLast(`Download as ${format}`)}
onAsk={() => setLast("Chat opened with the table attached")}
>
<ArtifactToolbarButton aria-label="Share Failed runs this week" onClick={() => setLast("Share")}>
<Share2 aria-hidden />
</ArtifactToolbarButton>
</ArtifactToolbar>
</div>
<p className="text-xs text-muted-foreground">{last}</p>
</div>
</TooltipProvider>
)
}<ArtifactToolbar>
| Prop | Type | Default | Description |
|---|---|---|---|
| titlerequired | string | — | The artifact's name, in every button's accessible name: "Download Failed runs". |
| maximised | boolean | undefined | false | Whether the artifact is maximised now: the button's name is then Restore rather than Maximise. |
| onMaximisedChange | ((maximised: boolean) => void) | undefined | — | Called with the state the person asks for. Without it, there's no maximise button. |
| downloads | ArtifactDownload[] | undefined | — | The formats it downloads as: one is a button, more a menu. |
| onDownload | ((format: string) => void) | undefined | — | Called with the format the person picks; the app makes the file. Without it, there's no download. |
| onAsk | (() => void) | undefined | — | Opens the app's chat with this artifact attached ("Ask about this"). Without it, there's no ask button. |
| locked | { [K in ArtifactToolbarControl]?: string | null | undefined } | undefined | — | Why a control can't be used now, by control. It stays focusable, marked `aria-disabled`, and says why. A control whose reason is `null` or left out is usable. |
| children | React.ReactNode | undefined | — | More actions, as `ArtifactToolbarButton`s, after the built-in ones. |
| className | string | undefined | — | Classes for the root, merged with Candor's. |
<ArtifactToolbarButton>
One more action in an ArtifactToolbar, so the arrow keys reach it: a small ghost button. Name it, with the artifact's title, in aria-label when it shows only an icon.
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | undefined | — | Classes for the button, merged with Candor's. |
Also takes the props of Omit<ToolbarPrimitive.Button.Props, "className" | "render">.
Strings
The fixed words, in English by default. Change any of them under artifactToolbar in <LocaleProvider strings={{ … }}>; the table is exported as artifactToolbarStrings.
| Key | English |
|---|---|
| toolbar | Actions for {title} |
| maximise | Maximise {title} |
| restore | Restore {title} |
| download | Download {title} |
| downloadAs | Download {title} as {format} |
| ask | Ask about this: {title} |
| askShort | Ask about this |
Types
- ArtifactDownload
- One format the artifact downloads as: its id, passed to `onDownload`, and the words for it ("CSV").
{ /** Passed to `onDownload`: "csv", "png". */ format: string; /** The format's words; defaults to `format`. */ label?: string | undefined; }- ArtifactToolbarControl
- The controls a reason can lock.
"maximise" | "download" | "ask"