REFERENCE
SDK Demos
How to use @asgard-js/core and @asgard-js/react, with demos you can try on the page.
Canvas Card
The agent can draw a chart or a layout for the user: one self-contained HTML/SVG fragment
that the SDK renders as a canvas card. The built-in <Chatbot> handles it; there is nothing
to wire.
The Markup Is Untrusted
Canvas content is generated per conversation by the model and may contain
<style>and<script>. Injecting it into the host page would hand that page's origin — its cookies, its storage, its DOM — to content the host did not author.Rendering it yourself requires isolationIt must go in an isolated browsing context with scripting allowed but same-origin access denied. In a browser that means an iframe sandboxed without
allow-same-origin, fed throughsrcdoc.That isolation also keeps the fragment off the network, which is expected — a canvas is authored to be self-contained.
The SDK's built-in
CanvasTemplatealready does exactly this. You only deal with it if you bypass the built-in rendering entirely.Types
interface CanvasMessageTemplate {
type: "CANVAS";
title?: string; // card title; the renderer shows only this
canvas: { html: string };
}titleis the only title source — do not extract one from the markup.Folded into the thread it takes this shape:
type ConversationCanvasMessage = {
type: "canvas";
messageId: string;
html: string;
title?: string;
isDrawing: boolean; // true = still arriving; false = the authoritative fragment landed
traceId?: string;
};Streaming: the Deltas Only Exist to Show It Taking Shape
A canvas travels over
asgard.message.canvas.start/.delta/.complete.The
htmloncompleteis authoritative. The intermediate deltas exist purely so the card can be shown taking shape; a client that ignored every delta renders the identical document from that field alone.While
isDrawingis true,htmlis a prefix that is still growing, not a complete document.Theming
The canvas lives in an iframe and cannot reach the host's CSS. The SDK resolves seven concrete values with
resolveCanvasTheme()and hands them over:Field Purpose fg/bgForeground / background accentEmphasis: the data itself (bars, lines, highlights) and anything clickable mutedDe-emphasized text: labels, captions, axes borderHairlines, card outlines, dividers padding/selectionPadding and selection color The first five names are a contract with the backend's
show_canvastool description — do not rename them.It reads computed colors, not CSS variablesresolveCanvasTheme()reads the computedcolor/background-colorof real elements rather than custom properties like--fg/--surface.That was learned the expensive way: the variable-reading version missed entirely on a design system that calls its main text color
--text-primary, so the text color fell back to near-white while--surfaceresolved to#ffffffin light mode — white on white, every pixel present, nothing visible, and readable only by luck on a dark host.A computed color has none of those problems: it is always a resolved
rgb(...), always reflects the theme in force, and requires no knowledge of what the host calls its tokens or what format they are in. The background also walks up the ancestor chain — the card itself may be transparent, and an iframe with no stated background is white.To override,
CanvasTemplatetakestheme?: Partial<ResolvedCanvasTheme>.See Also
- Message Templates — the full template catalog
- Question Card — the other agent-initiated interactive card