quarto-value-box

Installation

You can add this extension to any web-based project format (e.g. reveal-js, html) by running

quarto add bergam0t/quarto-value-box

Then add the filter to the list of extensions in your document header.

---
filters:
  - value-box
---

The Basics

Simple boxes

Value boxes

A simple value box can help make points stand out…

::: {.value-box}
**Value boxes**

A simple value box can help make points stand out...
:::

Values

Or display a metric

60

Number of bibbles bobbled this week

::: {.value-box value=60}
Number of bibbles bobbled this week
:::

Icons

Or display a metric with an icon

60

Number of bibbles bobbled this week

::: {.value-box value=60 icon="bi-arrow-down-up" icon-size="3rem"}
Number of bibbles bobbled this week
:::

Titles

Passing title adds a small label above the value — useful when the value alone needs naming.

Bibbles bobbled
60

This week

::: {.value-box title="Bibbles bobbled" value="60" icon="bi-arrow-down-up" icon-position="left" icon-size="2em"}
This week
:::
Styled title
42

title-color and title-font-size work like their value equivalents

::: {.value-box title="Styled title" title-color="#ffd54f" title-font-size="1.3rem" value="42" color="bg-purple"}
**title-color** and **title-font-size** work like their value equivalents
:::

Delta / trend indicator

A delta renders a small badge next to the value, e.g. a change since the last period. The arrow is inferred from a leading +/- in the text unless delta-direction is set explicitly.

Revenue
$1.2M
+12%

This quarter

::: {.value-box title="Revenue" value="$1.2M" delta="+12%" color="bg-green"}
This quarter
:::

delta-color is never inferred from direction, because “up” is not always good news — a rising cost and a falling cost are both “up” or “down” depending on which one you’re looking at. Set the colour explicitly for a semantic red/green treatment:

Operating cost
$430K
-8%

Lower is better here, so a fall is shown in green

::: {.value-box title="Operating cost" value="$430K" delta="-8%" delta-color="#8bc34a" color="bg-navy"}
Lower is better here, so a fall is shown in green
:::

Linked boxes

Set href to wrap the whole box in a link — it gets a subtle hover lift/shadow (static boxes don’t wobble). Add target="_blank" to open it in a new tab; that automatically adds rel="noopener noreferrer" too.

Hover over the box below to see it lift:

::: {.value-box title="Documentation" value="README"
  href="https://github.com/Bergam0t/quarto-value-box?tab=readme-ov-file"
  target="_blank" icon="bi-box-arrow-up-right" color="bg-slate"}
Opens in a new tab
:::

Size and Alignment

Horizontal Alignment

While by default we left-align, you might prefer center alignment with the align parameter

Here’s a more advanced type of box with an icon and some formatting, but no value

::: {.value-box icon="bi-arrow-down-up" color="bg-amber" width="60%" align="center"}
Here's a more advanced type of box with an icon and some formatting, but no value
:::

Vertical Alignment

And we can also add vertical alignment options.

42

No valign specified

::: {.value-box icon="fa-brands fa-python" color="bg-blue" value="42" height="400px"}
No valign specified
:::
42

Top alignment specified

::: {.value-box icon="fa-brands fa-python" color="bg-blue" value="42" height="400px" valign="top"}
Top alignment specified
:::

Width

We can manually override the width.

42

No width specified - defaults to 80% of container

::: {.value-box icon="fa-brands fa-python" icon-position="left" color="bg-blue" value="42"}
No width specified - defaults to 80% of container
:::
42

Width of 30% specified.

::: {.value-box icon="fa-brands fa-python" icon-position="left" color="bg-blue" value="42" width="30%"}
Width of 30% specified.
:::

Height

And we can manually override the height.

42

Example with no height specified - it will fit the contents

::: {.value-box icon="fa-brands fa-python" icon-position="left" color="bg-blue" value="42"}
Example with no height specified - it will fit the contents
:::
42

Example with height of 400 pixels (400px) specified

::: {.value-box height="400px" icon="fa-brands fa-python" icon-position="left" color="bg-blue" value="42"}
Example with height of 400 pixels (400px) specified
:::

Minimum height & padding

If a box’s content is short (or height is set below the default floor), min-height and padding can be lowered to reclaim space — handy on busy slides.

42

Default min-height (100px) and padding (1.5rem)

::: {.value-box icon="bi-star" value="42"}
Default min-height (100px) and padding (1.5rem)
:::
42

Tightened min-height and padding

::: {.value-box min-height="40px" padding="0.5rem" icon="bi-star" icon-size="1.5rem" value="42" }
Tightened min-height and padding
:::

Icon position

Icons can be repositioned with the icon-position parameter. top is the default — the icon, value, and details all stay flush against the same edge for left/right alignment.

Step 1

Add logging steps for arrivals, queues, resource use, and departures

::: {.value-box icon="fa-solid fa-clipboard" value="Step 1" icon-size="2em"}
Add logging steps for arrivals, queues, resource use, and departures
:::
42

Left-aligned icon

::: {.value-box icon-position="left" icon="bi-star" value="42" icon-size="2em"}
Left-aligned icon
:::

Icon position (continued)

99

Right-aligned icon

::: {.value-box icon-position="right" icon="bi-star" value="99" icon-size="2em"}
Right-aligned icon
:::
7

Icon below text

::: {.value-box icon-position="bottom" icon="bi-star" icon-size="1.5rem" value="7"}
Icon below text
:::

Value position

The value can be repositioned relative to the details text with the value-position parameter, completely independently of icon-position.

42

Left-aligned value

::: {.value-box value-position="left" value="42" icon="bi-star" icon-size="1.5rem" }
Left-aligned value
:::
99

Right-aligned value

::: {.value-box value-position="right" value="99" icon="bi-star" icon-size="1.5rem"}
Right-aligned value
:::

Value below details

7
::: {.value-box value-position="bottom" value="7" icon="bi-star" icon-size="1.5rem"}
Value below details
:::

Text Position

We can also combine this with text position using the align parameter.

Note that icon-position and value-position are independent — an icon on the left doesn’t force the value into a row with it.

42

Left-aligned icon with right-aligned text

::: {.value-box icon-position="left" align="right" icon="bi-star" color="bg-blue" value="42"}
Left-aligned icon with right-aligned text
:::
42

Left-aligned icon AND left-aligned value, together

::: {.value-box icon-position="left" value-position="left" align="right" icon="bi-star" color="bg-teal" value="42"}
Left-aligned icon AND left-aligned value, together
:::
7

Icon below text, all centred

::: {.value-box icon="bi-star" icon-position="bottom" icon-size="1.5rem" color="bg-red" value="7" align="center"}
Icon below text, all centred
:::

Layout

Row layout

Wrap value boxes in .value-box-row for an equal-width, equal-height KPI strip — no more hand-rolling .columns/.column scaffolding or hand-setting height on every box to make them match. With no columns set, boxes lay out in a single non-wrapping row:

128

Signups this week — a longer line of detail text here to show the other boxes stretch to match its height

42

Open tickets

99%

Uptime

::: {.value-box-row}

::: {.value-box value="128" color="bg-teal"}
Signups this week
:::

::: {.value-box value="42" color="bg-amber"}
Open tickets
:::

::: {.value-box value="99%" color="bg-green"}
Uptime
:::

:::

Row-level defaults

Set shared styling attributes once on the row instead of repeating them on every box. A box that doesn’t set its own value inherits the row’s, and one that does (like the color override below) always wins.

::: {.value-box-row icon-position="top" color="bg-red" icon-size="2rem" width="90%" align="center"}

::: {.value-box href="https://podcast.hsma.co.uk/episodes" icon="bi bi-headphones"}
Click here to listen to our past episodes
:::

::: {.value-box href="https://hsma.co.uk" icon="fa-solid fa-chalkboard-user"}
Click here to find out more about the HSMA programme
:::

::: {.value-box href="https://hsma.co.uk/hsma_content/modules/modules.html" icon="bi bi-camera-reels" color="bg-blue"}
Click here to access our HSMA 6 content recordings, slides and sample code
:::

:::

Only the third box’s color was repeated — icon-position, icon-size, width and align were each set once on the row and picked up by all three boxes.

Grid layout - example

Set columns to switch to a grid: extra boxes wrap onto further rows once it’s full, with every row — not just each one individually — kept the same height.

Team A
12

Wins this season — a much longer line of detail text, to show every row in the grid stretches to match the tallest box anywhere in it

Team B
9

Wins

Team C
15

Wins

Team D
7

Wins

Team E
11

Wins

Team F
4

Wins

Grid layout - code

::: {.value-box-row columns="3"}

::: {.value-box value="12" color="bg-blue" title="Team A"}
Wins this season
:::

::: {.value-box value="9" color="bg-purple" title="Team B"}
Wins
:::

::: {.value-box value="15" color="bg-red" title="Team C"}
Wins
:::

::: {.value-box value="7" color="bg-olive" title="Team D"}
Wins
:::

::: {.value-box value="11" color="bg-slate" title="Team E"}
Wins
:::

::: {.value-box value="4" color="bg-pink" title="Team F"}
Wins
:::

:::

Icons

Supported icon types

42

Bootstrap icons


::: {.value-box icon="bi-star" icon-position="left" color="bg-blue" value="42"}
Bootstrap icons
:::
42

Font awesome icons

::: {.value-box icon="fa-brands fa-python" icon-position="left" color="bg-blue" value="42"}
Font awesome icons
:::
home
42

Material Symbols icons

::: {.value-box icon="home" icon-type="material" icon-position="left" color="bg-blue" value="42"}
Material Symbols icons
:::
home
42

Material Symbols icons (rounded)

::: {.value-box icon="home" icon-type="material-rounded" icon-position="left" color="bg-blue" value="42"}
Material Symbols icons (rounded)
:::

More supported icon types

42

Tabler icons

::: {.value-box icon="ti-star" icon-position="left" color="bg-blue" value="42"}
Tabler icons
:::
42

Phosphor icons

::: {.value-box icon="ph ph-star" icon-position="left" color="bg-blue" value="42"}
Phosphor icons
:::

Font Awesome Icon Sets

Font Awesome icons come in different styles, selected via a class prefix. fa-solid, fa-regular, and fa-brands are all available here, via the free Font Awesome CDN this extension loads.

Solid

Filled-in icons

::: {.value-box icon="fa-solid fa-star" icon-position="left" color="bg-amber" value="Solid (fa-solid)" value-font-size="80%" icon-size="2em"}
Filled-in icons
:::
Regular (fa-regular)

Outlined icons

::: {.value-box icon="fa-regular fa-star" icon-position="left" color="bg-teal" value="Regular" value-font-size="80%" icon-size="2em"}
Outlined icons
:::
Brands (fa-brands)

Logos, only available in this one style

::: {.value-box icon="fa-brands fa-python" icon-position="left" color="bg-blue" value="Brands" value-font-size="80%" icon-size="2em"}
Logos, only available in this one style
:::

Font Awesome also has Pro-only styles — fa-light, fa-thin, and fa-duotone — which aren’t demoed here, as they require a paid Font Awesome Pro kit and this extension only loads the free CDN build.

Using local files as icons

By passing in the path to an svg or png file, you can use any image as an ‘icon’.

42

Local svg file

::: {.value-box icon="example-icon.svg" color="bg-grey" value="42" align="center"}
Local svg file
:::

Local png file

::: {.value-box icon="example-icon.png" icon-size="300px" color="bg-blue" align="center"}
Local png file
:::

Colour & Typography

Icon Color

Font awesome, bootstrap icons, tabler icons, phosphor icons, and material symbols support recoloring

Bootstrap icons


::: {.value-box icon-color="red" icon="bi-star" icon-position="left" }
Bootstrap icons
:::
42

Font awesome icons

::: {.value-box icon-color="fuchsia" icon="fa-brands fa-python" icon-position="left" }
Font awesome icons
:::
home
42

Material Symbols icons

::: {.value-box icon-color="lime" icon="home" icon-type="material" icon-position="left" }
Material Symbols icons
:::

Icon Color (continued)

42

Tabler icons

::: {.value-box icon-color="cyan" icon="ti-star" icon-position="left" }
Tabler icons
:::
42

Phosphor icons

::: {.value-box icon-color="orange" icon="ph ph-star" icon-position="left" }
Phosphor icons
:::

Box colours - built in

You can also change the color parameter. A number of predefined colours are available: bg-blue, bg-navy, bg-teal, bg-green, bg-olive, bg-amber, bg-orange, bg-red, bg-pink, bg-purple, bg-slate, bg-grey

For details on how to change or add named colours, see the advanced customisation section in the readme.

bg-blue

bg-navy

bg-teal

bg-green

bg-olive

bg-slate

bg-red

bg-orange

bg-amber

bg-purple

bg-pink

bg-grey

Box colours - custom

color also accepts a raw CSS colour value directly — no new class needed — for anything starting with #, rgb(/rgba(, hsl(/hsla(, or var(.

color=“#c8102e”

color=“rgb(200, 16, 200)”

color=“rgba(200, 16, 46, 0.3)”

color=“hsl(13 74.5% 52.4%)”

color=“hsla(13 74.5% 52.4% / 0.5)”



<style>
:root { --demo-brand-color: #2BAC9A; }
</style>

color=“var(–demo-brand-color)”

Box colours - _brand.yml

Quarto compiles a project’s _brand.yml palette into CSS custom properties automatically, so color can reference it with var(...) too — no manual <style> block needed. This deck ships its own _brand.yml:

# _brand.yml
color:
  palette:
    accent: "#6F3D9E"
  primary: accent

color=“var(–quarto-scss-export-brand-accent)”

icon-color=“var(–quarto-scss-export-brand-accent)”

--quarto-scss-export-brand-accent names the accent palette entry directly — Quarto exports every resolved theme/brand value this way, in every format, so there’s no need to know format-internal names like reveal.js’s --r-link-color or Bootstrap’s --bs-primary.

icon-color/font-color/value-color/title-color/delta-color accept var(...) the same way.

Box colours - finding variable names

Render once, then grep the compiled theme CSS for the --quarto-scss-export- prefix to see every brand/theme value Quarto resolved, under its own name — no need to read Quarto’s SCSS source:

grep -o -- "--quarto-scss-export-[a-zA-Z0-9_-]*:[^;]*" path/to/theme.css
  • revealjs: <doc>_files/libs/revealjs/dist/theme/quarto-*.css
  • html/dashboard: <doc>_files/libs/bootstrap/bootstrap-*.min.css

The semantic roles (primary, secondary, success, …) are exported the same way, as --quarto-scss-export-primary etc. Bootstrap-based formats additionally expose those same roles under Bootstrap’s own names too (--bs-primary, --bs-secondary, …), if you’d rather use those instead:

::: {.value-box color="var(--bs-primary)" value="42"}
Uses the brand's primary colour on an html/dashboard render
:::

Font Sizing

The font for the general text can be tweaked with the font-size parameter

Standard

::: {.value-box}
Standard
:::

150% Font Size

::: {.value-box font-size="150%"}
150% Font Size
:::

REM units

::: {.value-box font-size="2rem"}
REM units
:::

EM units

::: {.value-box font-size="2em"}
EM units
:::

Font Color

Yellow Font

::: {.value-box font-color="yellow"}
Yellow Font
:::
Value

Value font follows icon font by default

::: {.value-box font-color="yellow"}
Yellow Font
:::
Value

But they can differ

::: {.value-box font-color="yellow" value="Value" value-color="fuchsia"}
But they can differ
:::

Including computed figures

Driving values, icons and colour using computed data

color and delta don’t have to be typed in by hand — since a value box is just a fenced div, a code cell can compute them and print the div’s markdown straight into the document with output: asis. The box’s body is ordinary content too, so a chart can go right inside it rather than sitting next to it: Python looks at a week-over-week change here, picks red or green depending on its sign, formats the delta string, and renders a matching sparkline as a small transparent PNG, base64-encoded so it can be embedded directly with no separate image file to manage:

import base64
import io
import matplotlib.pyplot as plt

weekly_sales = [82, 88, 91, 87, 95, 101, 108]
current, previous = weekly_sales[-1], weekly_sales[-2]
change_pct = (current - previous) / previous * 100

color = "bg-green" if change_pct >= 0 else "bg-red"
delta = f"{change_pct:+.1f}%"

fig, ax = plt.subplots(figsize=(10, 0.6))

# White, not red/green: the box's own `color` already signals direction, and
# a red/green line risks near-zero contrast against a same-hue bg-* (as
# white does against every box colour, matching the value/delta/details text).
ax.plot(weekly_sales, marker="o", linewidth=2, color="white")
ax.axis("off")
fig.patch.set_alpha(0)  # transparent, so it blends into the box's own colour
plt.tight_layout(pad=0)

buffer = io.BytesIO()
fig.savefig(buffer, format="png", dpi=150, transparent=True)
plt.close(fig)
sparkline_b64 = base64.b64encode(buffer.getvalue()).decode("ascii")
<Figure size 960x480 with 0 Axes>

Driven by computed data - the output

#| output: asis
print(f'::: {{.value-box title="Weekly sales" value="{current}" delta="{delta}" color="{color}" width="50%"}}')
print(f'<img src="data:image/png;base64,{sparkline_b64}" alt="weekly sales trend" style="width:100%; height:auto; display:block; margin:0.4rem 0;">')
print("Colour, delta and sparkline all follow the sign of `change_pct`, computed above")
print(":::")


Weekly sales
108
+6.9%

weekly sales trend Colour, delta and sparkline all follow the sign of ‘change_pct’, computed on the previous slide


output: asis tells Quarto to drop the cell’s printed text straight into the document as markdown, so the f-string-built ::: {.value-box ...} block above is parsed exactly as if it had been typed by hand — <img> tag included, since the box’s body accepts any content placed inside the fence, not just plain text.

Encoding the chart as a base64 data: URI rather than saving a separate PNG keeps the whole box self-contained in the rendered page, with no extra file to stage or deploy alongside it.

Flip weekly_sales[-1] below weekly_sales[-2] and the box’s colour, its delta, and the sparkline all switch together, since they’re reading the same change_pct.

Simple Animation

Fragment types

Big text

We can use them with special named fragment types like ‘fade in, then semi out’ (this is also the default if you set fragment=“true”)

::: {.value-box fragment="fade-in-then-semi-out" value="Big text" icon="bi-arrow-down-up" icon-size="2rem" color="bg-olive" width="60%" align="center"}
We can use them with special named fragment types like 'fade in, then semi out'
(this is also the default if you set fragment="true")
:::
Big text

Or standard fragments

::: {.value-box fragment="fade-in-then-out" value="Big text" icon="bi-arrow-down-up" icon-size="2rem" color="bg-olive" width="60%" align="center"}
Or standard fragments
:::

Tada!

:::{.fragment}
Tada!
:::

All fragment types

Every fragment style shipped with this version of Reveal.js, one per box — advance through the slide to see each one in turn. All of them fade in on entry; the class name controls what (if anything) happens after that. See the Reveal.js docs for the full reference.

fade-in

Fades in, stays visible

fade-out

Starts visible, fades out

fade-up

Fades in while sliding up

fade-down

Fades in while sliding down

fade-left

Fades in while sliding left

fade-right

Fades in while sliding right

fade-in-then-out

Fades in, fades out next step

fade-in-then-semi-out

Fades in, dims next step (this extension’s default)

semi-fade-out

Starts visible, dims out

grow

Fades in while growing larger

shrink

Fades in while shrinking

zoom-in

Fades in while zooming from small

strike

Fades in with a strikethrough

Not shown: highlight-red/-green/-blue and their highlight-current-* variants. Reveal.js applies these by recolouring the fragment element’s own color, but value boxes set color inline on the value/details text for contrast against color/bg-*, which overrides it — so these six have no visible effect on a value box and are unsupported here.

Complex icon box layouts with index parameter

By using the ‘index’ parameter, we can determine the order that fragments appear by passing a number that indicates the order.

Left Column

This appears SECOND (Index 2)

::: {.value-box fragment="true" index="2" width="70%"}
This appears SECOND (Index 2)
:::

Right Column

This appears FIRST (Index 1)

::: {.value-box fragment="true" index="1" width="70%"}
This appears FIRST (Index 1)
:::

Advanced Usage

Escape hatch: id, extra classes and attributes

Beyond the parameters this extension defines, an #id and extra .classes pass through onto the rendered box, along with data-*/aria-* attributes and role/tabindex/lang. Anything else is left off rather than renamed to a data- attribute.

42

id, an extra class, ARIA attributes and a data-id (useful for revealjs auto-animate) all survive

<style>
.highlight-box { outline: 7px dashed gold; outline-offset: 4px; }
</style>


::: {.value-box #kpi-example .highlight-box value="42" role="group" aria-label="Sales this quarter" data-id="kpi-example"}
id, an extra class, ARIA attributes and a data-id (useful for revealjs auto-animate) all survive
:::

Advanced Animation

data-id and auto-animate

data-id is what actually drives Reveal.js auto-animate: give two consecutive slides auto-animate="true" in the heading, give a value box the same data-id on both, and Reveal.js treats it as the same element and smoothly morphs its position, size and colour between them as you advance. The next two slides are that pair — present the deck (not the static preview pane) to see it animate.

Auto-animate: Growth

42

New customers this quarter

Auto-animate: Growth

1,284

New customers this quarter — up from 42 last quarter

## Auto-animate: Growth {auto-animate="true"}

::: {.value-box data-id="autoanimate-demo" value="42" width="30%" color="bg-blue" align="center"}
New customers this quarter
:::

## Auto-animate: Growth {auto-animate="true"}

::: {.value-box data-id="autoanimate-demo" value="1,284" width="90%" color="bg-green" align="left"}
New customers this quarter — up from 42 last quarter
:::

The matching data-id is doing all the work here — everything else about the box (value, width, color, align) is free to differ between the two slides.

More auto-animate examples

The Growth pair changed several properties at once. Auto-animate isn’t limited to any fixed list of attributes — it interpolates whatever CSS the matched element ends up with, so anything on the box that becomes a CSS property can be animated:

  • Sizewidth, height, padding, value-font-size, min-height… a box can grow or shrink
  • Position — move a box anywhere on the slide via outer-extra-style="margin-left:...;" (or any other positioning CSS)
  • Colourcolor, font-color, value-color, icon-color, delta-color
  • Anything else expressible as CSS — opacity, rotation, border-radius — via the *-extra-style escape hatches from the previous section, since those pass straight through to the element’s style=

The next two pairs isolate shrink and movement on their own, so it’s clear which attribute is driving which part of the animation.

Auto-animate: Headline

128%

Year-over-year growth

Auto-animate: Headline

128%

YoY growth

Only value-font-size, width, padding and min-height changed between those two slides — the same headline stat condenses into a small summary tile, e.g. to make room as supporting detail appears elsewhere on the next slide of a real deck.

## Auto-animate: Headline {auto-animate="true"}

::: {.value-box data-id="shrink-demo" value="128%" value-font-size="4rem" width="70%" color="bg-purple" align="center"}
Year-over-year growth
:::

## Auto-animate: Headline {auto-animate="true"}

::: {.value-box data-id="shrink-demo" value="128%" value-font-size="1.3rem" width="20%" padding="0.5rem" min-height="40px" color="bg-purple" align="center"}
YoY growth
:::

Auto-animate: Focus

7

Days until launch

Auto-animate: Focus

7

Days until launch

Here only outer-extra-style and icon changed — same size, same colour, same value, just a different margin-left — so the box visibly slides across the slide with nothing else moving.

## Auto-animate: Focus {auto-animate="true"}

::: {.value-box data-id="movement-demo" value="7" width="35%" color="bg-amber" icon="fa-solid fa-clock" icon-position="left"}
Days until launch
:::

## Auto-animate: Focus {auto-animate="true"}

::: {.value-box data-id="movement-demo" outer-extra-style="margin-left:60%;" value="7" width="35%" color="bg-amber" icon="fa-solid fa-rocket" icon-position="left"}
Days until launch
:::