Typst Figures
image() for the raw image. figure() for caption, numbering, and cross-referencing. grid() for side-by-side layouts.
The basics
// Bare image
#image("diagram.png")
// With width
#image("diagram.png", width: 80%)
// Captioned figure with reference
#figure(
image("diagram.png", width: 80%),
caption: [System architecture overview.]
) <arch>
See @arch for the architecture.Side-by-side figures
#figure(
grid(
columns: (1fr, 1fr),
column-gutter: 1em,
image("first.png"),
image("second.png"),
[(a) First view],
[(b) Second view],
),
caption: [Two views of the system.]
) <both>Three figures, individual captions
#grid(
columns: (1fr, 1fr, 1fr),
column-gutter: 1em,
figure(image("a.png"), caption: [First.]),
figure(image("b.png"), caption: [Second.]),
figure(image("c.png"), caption: [Third.]),
)Image options
| Option | Use |
|---|---|
| width: 80% | 80% of container width |
| width: 5cm | Fixed 5cm width |
| height: 4cm | Fixed height |
| alt: "Description" | Accessibility alt text |
| fit: "contain" | Aspect-ratio behavior |
Supported formats
- PNG, JPEG — raster, embedded as-is
- SVG — vector, recommended for diagrams
- GIF — single-frame static
- PDF — embedded vector, useful for matplotlib/TikZ output
Common mistakes
- Forgetting
#prefix. All Typst function calls in markup mode start with#. - Using paths with backslashes. Forward slashes only, even on Windows:
image("subfolder/file.png"). - Using width without %.
width: 80is a syntax error. Usewidth: 80%orwidth: 5cm. - Forgetting the label angle brackets. Labels are
<name>, references are@name.
TypeTeX gives you a free in-browser Typst editor with image upload, figure templates, and instant compile.
Start writing in TypstFrequently Asked Questions
Use #image("path/to/file.png") for a bare image, or wrap in #figure(image(...), caption: [Your caption]) for a captioned, numbered, referenceable figure. Typst supports PNG, JPEG, SVG, GIF, and PDF images.
Pass width as an argument: #image("file.png", width: 80%) for 80% of the surrounding container, or width: 5cm for fixed width. You can also use width: auto (default — the file's natural size). Same for height.
Wrap image() in figure(): #figure(image("file.png", width: 80%), caption: [Your caption]). The figure environment auto-numbers ('Figure 1') and lets you reference with @label after attaching <label>.
Attach a label after the figure: #figure(...) <my-fig>. Then reference with @my-fig in body text: 'See @my-fig.' Typst automatically inserts 'Figure N' (or whatever the figure kind is). Customize with #set ref(...) if needed.
Use grid() for layout, then optionally wrap individual images in figure(): #grid(columns: (1fr, 1fr), column-gutter: 1em, figure(image("a.png"), caption: [(a)]), figure(image("b.png"), caption: [(b)])). Each gets its own caption (a)/(b).
Yes. #image("diagram.svg") and #image("chart.pdf") work the same as PNG/JPEG. SVG is recommended for vector diagrams (rasterized only when needed). PDF figures are embedded as-is — useful for matplotlib output and TikZ diagrams compiled separately.
Wrap figure() in #place(...) for explicit positioning (top, bottom, etc.), or use #figure(placement: top, ...) — Typst will float the figure to the top of the next page when needed. Most figures don't need explicit placement; Typst handles flow automatically.
Scale: #image("file.png", width: 50%) sets size; for transforms use #scale(80%, image("file.png")). Rotate: #rotate(45deg, image("file.png")). Both scale and rotate work on any content, not just images.
Typst is much simpler. No \includegraphics + figure environment + caption + label dance — it's all one figure() call. No subfigure package — use grid() with multiple figure() calls. Cross-references are @label (one character) instead of \ref{}. And Typst auto-handles float placement without [tbph] hints.