Skip to content
misoto22 design

Diagrams

DiagramExportMenu

Taking the figure off the page: PNG, JPEG, WebP, SVG and a 1200×630 share card.

Ships from@misoto22/design/diagrams

When to reach for it

It does the export rather than emitting a format name, because the interesting half — baking custom properties into real colours before serialising — is the half a caller would not know to write.

Examples

default

Request path2 elements and 1 relationships.CLOUDCloudFrontCDNSERVICEAPIFastAPI

2 elements and 1 relationships.

  • CloudFront (cloud) — CDN
  • API (backend) — FastAPI
  • CloudFrontAPI: HTTPS

Notes

Taking the figure off the page: five files, one menu.

WHY THE MENU DOES THE WORK rather than handing back a format: every one of these exports is the same six steps — find the <svg>, walk it with getComputedStyle to bake the custom properties into real colours, serialise, rasterise, name the file, hand it to the browser — and only the last two differ between them. A menu that emitted 'png' and left the caller to do the rest would be a menu that every consumer reimplements, badly, and the interesting half (a serialised SVG resolves var(--ink) to nothing and comes out invisible) is exactly the half a caller would not know to write.

onExport is still there for a page with its own pipeline — a server-side renderer, a different frame size — and taking it turns everything below into a no-op.

What each format actually is, stated rather than implied.

SVG is the artwork with resolved colours. It is editable and it is the only lossless one, but it carries no web fonts: a machine without the family renders it in a fallback, so type metrics will differ.

PNG, JPEG and WebP are the browser's own rasteriser re-drawing that SVG at 2×. Not a screenshot — antialiasing and any effect a page stylesheet applied from OUTSIDE the <svg> are not in it. JPEG has no alpha, so it is flattened onto the resolved paper colour rather than onto black, which is what a transparent PNG becomes when a format with no transparency is asked to hold it.

The share card is a 1200 × 630 frame with the title on it and the whole diagram letterboxed inside — never cropped. A card that cropped to fill the frame would be a picture of a different diagram.

Props

DiagramExportMenu props
PropTypeDefaultDescription
targetRefrequiredRefObject<HTMLElement | SVGSVGElement | null>The `<svg>` to export, or an element containing exactly one. A ref rather than a selector, because a page can hold several figures and a selector would export whichever the document happened to reach first.
titlerequiredstringNames the file, and is printed on the share card.
classNamestring
onExport(format: ExportFormat) => void | Promise<void>Runs instead of the built-in export — for a caller with its own pipeline.
onResult(result: ExportResult) => voidTold what happened, so a page can raise a toast.
triggerReactNodeReplaces the trigger.

Parts

Composed at the call site rather than configured through props, so a layout this component did not anticipate is still expressible.

exportFigure

One figure, one format, one file.

Exported so a page can wire a keyboard shortcut or its own button to exactly what the menu does, without reimplementing the six steps.

Takes no props of its own.

Types

TSX
export type ExportFormat = 'png' | 'jpeg' | 'webp' | 'svg' | 'share-card'

Accessibility

  • A failed export is reported through onResult rather than swallowed: a click that quietly does nothing is indistinguishable from a broken button.