Card registry
Free · MITRenders one card from the registry. Three honest fallbacks, each with the service's text summary: the app doesn't know this card; its data doesn't fit (and how); or it failed while drawing.
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/card-registry
Brings in: collapsible, degraded-panel, locale · npm: lucide-react@^1.67.0
Usage
"use client"
import { CardRegistryProvider, defineCard } from "@/components/card-registry"
import { MessageContent } from "@/components/message-content"
// Your app's cards: what each one needs, checked before it draws.
const cards = {
order: defineCard<{ id: string; status: string; total: string }>({
label: "Order",
check: (p) => (typeof p === "object" && p && "id" in p && "status" in p ? null : "it needs an id and a status"),
render: (p) => (
<div className="w-fit rounded-lg border bg-card px-3 py-2 text-sm">
Order <span className="font-medium">#{p.id}</span> · {p.status} · {p.total}
</div>
),
}),
}
export default function Example() {
return (
<CardRegistryProvider cards={cards}>
<MessageContent
className="max-w-lg"
blocks={[
{ kind: "card", card: "order", props: { id: "4821", status: "Shipped", total: "$42.00" }, summary: "Order #4821, shipped, $42.00" },
{ kind: "card", card: "order", props: { id: "4830" }, summary: "Order #4830 (incomplete data)" },
{ kind: "card", card: "map", props: {}, summary: "A delivery map this app can’t show" },
]}
/>
</CardRegistryProvider>
)
}<Card>
| Prop | Type | Default | Description |
|---|---|---|---|
| namerequired | string | — | Which card to draw, from the registry. |
| propsrequired | unknown | — | The card's data, checked before it draws. |
| summaryrequired | string | — | The plain-text version, shown when the card can't be. |
<CardRegistryProvider>
Makes cards available to every message below it. Cards not listed here fall back to their summary.
| Prop | Type | Default | Description |
|---|---|---|---|
| cardsrequired | Record<string, AnyCard> | — | Your app's cards by name, made with defineCard. |
| childrenrequired | React.ReactNode | — | What goes inside. |
Functions
defineCard(card: CardDefinition<P>)Define a card with typed props; the check is what makes the cast safe.
Strings
The fixed words, in English by default. Change any of them under cardRegistry in <LocaleProvider strings={{ … }}>; the table is exported as cardRegistryStrings.
| Key | English |
|---|---|
| showAsText | Show it as text |
| unknown | This reply includes a “{name}” card this app can’t show. |
| invalid | The {label} couldn’t be shown: {problem} |
| failed | The {label} failed while drawing. |
Types
- CardDefinition
- A card an agent's reply can carry. `check` decides whether the props are the shape `render` needs: it returns null when they are, or a sentence saying what's wrong. Cards are data from a model; nothing renders until the check passes.
{ /** What it is, in a few words, for fallbacks: "Query results". */ label: string check: (props: unknown) => string | null render: (props: P) => React.ReactNode }