
Cross-References in Quarto: Figures, Tables, Sections, and Equations
Number and link to figures, tables, sections, and equations automatically
Learn to cross-reference in Quarto — label a figure, table, section, or equation and reference it by number with @fig-, @tbl-, @sec-, and @eq-. Quarto numbers everything and keeps the links live, so your report reads like a paper.
- One pattern for everything: give the element a prefixed label (
#fig-,#tbl-,#sec-,#eq-,#lst-), then write@fig-…,@tbl-…,@sec-…,@eq-…in the prose. Quarto inserts the number and a link. - The number is automatic and live. Reorder your figures or insert a table above another, re-render, and every reference updates — you never hand-type “Figure 1” again.
- A figure or table needs a caption to be referenceable. A prefixed label with no caption is not registered, and
@fig-…renders as a broken?@fig-…. - Section references need
number-sections: truein the document; without it there is no number to link to. This page enables it, which is why its headings are numbered. - Change how a reference reads with bracket syntax:
[Fig @fig-x]for a custom prefix,[-@fig-x]for the bare number,[@fig-a; @fig-b]to group several.

1 Introduction
A report that reads like a paper refers to its figures, tables, sections, and equations by number — “see Figure 2”, “the model in Equation 1” — and those numbers stay correct when you add, remove, or reorder content. Doing that by hand is a trap: one inserted figure and every later “Figure N” is wrong. Quarto does the numbering and the linking for you, across every kind of element, from one small convention.
The convention is two steps: label the element with a type-specific prefix, then reference it with @ plus that label. This lesson walks the four you reach for most — figures, tables, sections, and equations — plus sub-references and the more specialised elements (code listings, callouts, theorems, diagrams, videos). The full scheme lives in the Quarto cross-references documentation; this is the practical path through it.
Because it is a Quarto feature guide, the lesson is self-demonstrating: every reference you see resolve below is pointing at a real, labelled element on this very page. Read the source, then look at the number Quarto produced from it. (This page also sets number-sections: true so that section references work — that is why its headings carry numbers.)
2 The core pattern: label, then reference
Every cross-reference is the same two moves. First, attach a label whose prefix tells Quarto what kind of thing it is. Second, write @ followed by that label wherever you want the number to appear. Quarto matches them up at render time, assigns the number, and inserts a hyperlink.
The prefix is what selects the counter — figures count separately from tables, tables from equations, and so on:
| Element | Label prefix | Reference | Renders as |
|---|---|---|---|
| Figure | #fig- |
@fig-… |
Figure 1 |
| Table | #tbl- |
@tbl-… |
Table 1 |
| Section | #sec- |
@sec-… |
Section 1 |
| Equation | #eq- |
@eq-… |
Equation 1 |
| Code listing | #lst- |
@lst-… |
Listing 1 |
| Callout / theorem | #tip-, #thm-, … |
@tip-…, @thm-… |
Tip 1 / Theorem 1 |
Two rules apply to all of them. Use hyphens, not underscores, in labels — an underscore can trip up rendering in some output formats. And a floating element (a figure or table) must have a caption to be referenceable: the caption is what registers the number.
3 Cross-reference a figure
Any code chunk that draws a plot becomes a figure. Give it a label that starts with fig- and a fig-cap, and it is referenceable. Here is the source, then what it renders:
```{r}
#| label: fig-fuel
#| fig-cap: "Heavier cars burn more fuel: mileage falls steadily as weight rises."
#| fig-alt: "Scatter plot of car weight against miles per gallon; points trend downward from top-left to bottom-right."
#| fig-width: 7
#| fig-height: 4
library(ggplot2)
ggplot(mtcars, aes(wt, mpg)) +
geom_point(color = "#3a86d4", size = 2.5) +
labs(x = "Weight (1000 lbs)", y = "Miles per gallon") +
theme_minimal()
```library(ggplot2)
ggplot(mtcars, aes(wt, mpg)) +
geom_point(color = "#3a86d4", size = 2.5) +
labs(x = "Weight (1000 lbs)", y = "Miles per gallon") +
theme_minimal()
Now write @fig-fuel in the prose and Quarto turns it into a numbered link. The relationship is unmistakable (Figure 2) — and that number was inserted by Quarto, not typed by hand.
A Markdown image works the same way: put a #fig--prefixed id in braces after it, and give it caption text (the bracket text). This is the form you use for a screenshot or a diagram file:
{#fig-workflow}
The pipeline has three stages (@fig-workflow).For everything about captioning, sizing, and laying figures out, see the dedicated figures lesson.
4 Cross-reference a table
Tables follow the identical pattern with a tbl- prefix. Give the code cell a #| label: starting with tbl- and a #| tbl-cap:, then reference it with @tbl-…. Here we summarise mtcars in base R and tabulate it with knitr::kable():
```{r}
#| label: tbl-mpg
#| tbl-cap: "Average miles-per-gallon by cylinder count."
library(knitr)
agg <- aggregate(mpg ~ cyl, data = mtcars, FUN = mean)
agg$mpg <- round(agg$mpg, 1)
kable(agg, col.names = c("Cylinders", "Mean MPG"))
```library(knitr)
agg <- aggregate(mpg ~ cyl, data = mtcars, FUN = mean)
agg$mpg <- round(agg$mpg, 1)
kable(agg, col.names = c("Cylinders", "Mean MPG"))| Cylinders | Mean MPG |
|---|---|
| 4 | 26.7 |
| 6 | 19.7 |
| 8 | 15.1 |
Writing @tbl-mpg now produces a numbered link: fuel economy drops steadily as cylinder count rises (Table 2). A hand-written Markdown table is referenceable too — put {#tbl-…} in its caption line instead of a cell option. The tables lesson covers kable, gt, and captioning in full.
5 Cross-reference a section
Sections are the one type with an extra requirement. To reference a heading, add a #sec--prefixed id to it and enable number-sections in the document — without a number, there is nothing to link to.
## Methods {#sec-methods}
We describe the model in @sec-methods.---
title: "My report"
number-sections: true
---This page has number-sections: true set, so its section references resolve. The two sections above carry the ids #sec-figures and #sec-tables; referencing them gives Section 3 and Section 4 — real, numbered links that track the headings even if you reorder the document. See the sections documentation for the details.
6 Cross-reference an equation
Label a display equation by putting {#eq-…} immediately after the closing $$, on the same line. Then reference it with @eq-….
The simple linear model (@eq-line) fits a straight line:
$$
y = \beta_0 + \beta_1 x
$$ {#eq-line}Which renders as — the simple linear model (Equation 1) fits a straight line:
\[ y = \beta_0 + \beta_1 x \tag{1}\]
Quarto numbers the equation on the right and turns @eq-line into a link to it.
7 Sub-references: address each panel
When one figure holds several panels, you can reference the whole thing or any single panel. Give the chunk a fig- label and a fig-subcap list (one caption per panel) with layout-ncol; Quarto labels the panels (a), (b) and makes each addressable.
```{r}
#| label: fig-views
#| fig-cap: "Two views of what drives fuel efficiency."
#| fig-subcap:
#| - "By weight"
#| - "By horsepower"
#| layout-ncol: 2
#| fig-width: 5
#| fig-height: 4
library(ggplot2)
ggplot(mtcars, aes(wt, mpg)) +
geom_point(color = "#3a86d4") + theme_minimal()
ggplot(mtcars, aes(hp, mpg)) +
geom_point(color = "#3a86d4") + theme_minimal()
```library(ggplot2)
ggplot(mtcars, aes(wt, mpg)) +
geom_point(color = "#3a86d4") + theme_minimal()
ggplot(mtcars, aes(hp, mpg)) +
geom_point(color = "#3a86d4") + theme_minimal()

Now @fig-views points at the pair, while @fig-views-1 and @fig-views-2 point at the individual panels: weight is in Figure 3 (a) and horsepower in Figure 3 (b). The same idea works for tables (tbl-subcap) and for grouping image files in a {#fig-…} div with inner #fig-… ids.
8 Change how a reference reads
The default reference reads “Figure 2”. Bracket syntax lets you change the wording without touching the label — useful for a house style that abbreviates, or a sentence that already says “Figure”:
| Syntax | Renders |
|---|---|
@fig-fuel |
Figure N (default prefix) |
[Fig @fig-fuel] |
Fig N (custom prefix) |
[-@fig-fuel] |
N (bare number) |
[@fig-fuel; @fig-views] |
grouped into one reference |
Because the labels on this page are real, those forms resolve live. Default: Figure 2. Custom prefix: Fig 2. Bare number, handy after you have already written the word “Figure”: 2. And grouped, which collapses a list into a tidy single reference: Figure 2, Figure 3.
9 Cross-reference other elements
The same label-then-@ pattern extends beyond the big four. These are the ones you meet less often, with the syntax you need.
9.1 Callouts
Give a callout an id with the right prefix and reference it like anything else. Here is a real one:
::: {#tip-crossref .callout-tip}
## A referenceable tip
Add an id starting with `#tip-` to make a callout cross-referenceable.
:::
See @tip-crossref for the trick.Add an id starting with #tip- to make a callout cross-referenceable.
See Tip 1 for the trick. Each callout type has its own prefix:
| Callout type | Prefix |
|---|---|
note |
#nte- |
tip |
#tip- |
warning |
#wrn- |
important |
#imp- |
caution |
#cau- |
9.2 Code listings
To reference a block of code by number, add a lst-label (with an lst- prefix) and an lst-cap to the chunk, then use @lst-…:
```{r}
#| lst-label: lst-summary
#| lst-cap: "Summarise fuel economy by cylinder count."
aggregate(mpg ~ cyl, data = mtcars, FUN = mean)
```
The code in @lst-summary produces the per-cylinder means.9.3 Theorems, diagrams, and videos
- Theorems and proofs use a div with a
#thm-label (and siblings#lem-for a lemma,#cor-for a corollary,#def-for a definition,#prp-for a proposition). Put the theorem name in the first heading; reference with@thm-…. A.proofdiv is not numbered, so it cannot be referenced. - Diagrams made with a
{mermaid}or{dot}block become figures: wrap them in a::: {#fig-…}div with a caption and reference with@fig-…. - Videos work the same way — a
::: {#fig-…}div around ashortcode, referenced as a figure. If you want videos to have their own “Video 1” counter instead of sharing the figure counter, define a custom cross-reference type:
---
crossref:
custom:
- kind: float
reference-prefix: Video
key: vid
---A custom type with key: vid is then labelled #vid-… and referenced @vid-…. The same mechanism produces supplemental figures (“Figure S1”, “Figure S2”) with a separate counter.
For PDF output, Quarto can also emit a list of all figures, tables, or listings with the LaTeX commands \listoffigures, \listoftables, and \listoflistings, and you can retitle them with the lof-title / lot-title / lol-title options.
10 Common issues
A reference renders as literal ?@fig-name (a broken link). Quarto could not resolve that label. For a figure or table, two things must line up: the label starts with the right prefix (fig-, tbl-) and the element has a caption. A labelled figure with no fig-cap is not registered as referenceable, so there is nothing for @fig-name to point at. Add the caption and check the spelling matches exactly.
@sec-… does not produce a number. Section references need number-sections: true in the document and a #sec--prefixed id on the heading. Miss either and the reference cannot resolve to a number.
A reference breaks after a rename. The @-reference must match the label character for character. If you rename a chunk’s label, update every @… that points at it. Prefer hyphens over underscores in labels — underscores can cause rendering issues in some formats.
11 Frequently asked questions
Give the figure a label that starts with fig- (e.g. #| label: fig-trend for a code chunk, or {#fig-trend} on a Markdown image) and a caption, then write @fig-trend in your text. Quarto inserts the correct number and a link, and renumbers automatically if you reorder the document.
The label could not be resolved. The two usual causes are a missing caption (a fig-/tbl--labelled element needs one to be registered) and a label that does not match the reference exactly. Add the caption and check the spelling.
Add a #sec--prefixed id to the heading — ## Methods {#sec-methods} — and set number-sections: true in the document front matter. Then @sec-methods renders as a numbered, linked “Section N”. Without number-sections, there is no number to link to.
Each element type has its own label prefix and counter: fig- for figures, tbl- for tables, sec- for sections, eq- for equations, lst- for code listings, and callout/theorem prefixes like tip-, nte-, thm-, def-. You reference any of them with @ plus the label, e.g. @tbl-summary.
Use bracket syntax around the reference: [Fig @fig-x] gives a custom prefix (“Fig 2”), [-@fig-x] gives just the number (“2”), and [@fig-a; @fig-b] groups several into one reference. The label itself stays unchanged.
Task 1. You have a code chunk that draws a boxplot of iris$Sepal.Length by Species. Write the chunk options that make it cross-referenceable as @fig-sepal, then write a sentence that references it.
Two chunk options are required for a figure cross-reference: a label that starts with the figure prefix, and a caption. The reference itself is @ plus the label.
```{r}
#| label: fig-sepal
#| fig-cap: "Sepal length differs across the three iris species."
#| fig-alt: "Boxplot of sepal length grouped by species; virginica is highest, setosa lowest."
library(ggplot2)
ggplot(iris, aes(Species, Sepal.Length)) +
geom_boxplot(fill = "#3a86d4") +
theme_minimal()
```Then in the prose: Setosa flowers have the shortest sepals (@fig-sepal). The fig--prefixed label and the fig-cap are both required for @fig-sepal to produce a number.
Task 2. Write a labelled display equation for the area of a circle and a sentence that references it by number.
The area of a circle (@eq-area) grows with the square of the radius:
$$
A = \pi r^2
$$ {#eq-area}The {#eq-area} id goes immediately after the closing $$; @eq-area then renders the numbered link.
You write ## Methods {#sec-methods} and reference it with @sec-methods, but the reference does not produce a number. What is the most likely cause?
A. You need a caption on the section. B. number-sections: true is not set in the document. C. Section references are not supported in HTML.
B. Section cross-references require number-sections: true in the front matter — without it there is no number to link to. (Sections do not take captions, and HTML supports them fully.)
12 Conclusion
Cross-referencing in Quarto is one convention applied everywhere: label the element with a type prefix — #fig-, #tbl-, #sec-, #eq-, #lst- — then reference it with @ and that label. Quarto assigns the number, inserts the link, and keeps both correct as the document changes. Remember the two gotchas: figures and tables need a caption to be referenceable, and section references need number-sections: true. Wire those in and your report cites its own figures, tables, and equations the way a paper does — automatically.
Reuse
Citation
@online{2026,
author = {},
title = {Cross-References in {Quarto:} {Figures,} {Tables,}
{Sections,} and {Equations}},
date = {2026-07-08},
url = {https://www.datanovia.com/learn/programming/quarto/cross-references},
langid = {en}
}