50 / 122 · Structured output
Diagram
A drawn answer with zoom, reset, and a full-bleed view; you hand it the rendered graphic.
message flow100%
Installation
npx shadcn@latest add "@assistant-ui/elements-diagram"
Usage
import { Diagram } from "@/components/elements/diagram";
<Diagram title="message flow" zoom={zoom} onZoomIn={zoomIn} onReset={reset}>
<MermaidSvg chart={chart} />
</Diagram>Props
title*stringWhat the diagram shows.
zoom*numberScale factor applied to the content. 1 is fit; the header prints it as a percentage.
children*React.ReactNodeThe rendered graphic. The element owns the frame and never parses or injects markup itself, so whatever renders your chart stays your choice.
onZoomIn() => voidCalled from the zoom-in control. Clamp the range yourself.
onZoomOut() => voidCalled from the zoom-out control.
onReset() => voidCalled to return to the default view.
onExpand() => voidCalled to open the diagram full screen.
classNamestringExtra classes merged onto the root.
Source
diagram.tsx"use client";
import { MaximizeIcon, MinusIcon, PlusIcon, RotateCcwIcon } from "lucide-react";
import { cn } from "@/lib/utils";
import { ghostButton, mono, paper } from "./surfaces";
export function Diagram({
title,
zoom,
children,
onZoomIn,
onZoomOut,
onReset,
onExpand,
className,
}: {
title: string;
zoom: number;
children: React.ReactNode;
onZoomIn?: () => void;
onZoomOut?: () => void;
onReset?: () => void;
onExpand?: () => void;
className?: string;
}) {
return (
<div
className={cn(
paper,
"flex w-full max-w-md flex-col overflow-hidden rounded-2xl",
className,
)}
>
<div className="flex items-center gap-1 px-3 py-2">
<span className="min-w-0 flex-1 truncate text-[13px] font-medium">
{title}
</span>
<span className={cn(mono, "text-foreground/30 shrink-0 tabular-nums")}>
{Math.round(zoom * 100)}%
</span>
<button
type="button"
aria-label="Zoom out"
onClick={onZoomOut}
className={cn(ghostButton, "size-7 shrink-0")}
>
<MinusIcon className="size-3.5" />
</button>
<button
type="button"
aria-label="Zoom in"
onClick={onZoomIn}
className={cn(ghostButton, "size-7 shrink-0")}
>
<PlusIcon className="size-3.5" />
</button>
<button
type="button"
aria-label="Reset the view"
onClick={onReset}
className={cn(ghostButton, "size-7 shrink-0")}
>
<RotateCcwIcon className="size-3.5" />
</button>
<button
type="button"
aria-label="Open full screen"
onClick={onExpand}
disabled={!onExpand}
className={cn(
ghostButton,
"size-7 shrink-0 disabled:pointer-events-none disabled:opacity-30",
)}
>
<MaximizeIcon className="size-3.5" />
</button>
</div>
<div className="border-foreground/[0.07] flex min-h-[10rem] items-center justify-center overflow-hidden border-t p-4">
<div
className="origin-center transition-transform duration-200 ease-out motion-reduce:transition-none"
style={{ transform: `scale(${zoom})` }}
>
{children}
</div>
</div>
</div>
);
}