quarto-dev / quarto-dev/quarto-cli
a11y: secondary text (blockquotes, captions, asides) fails WCAG AA color contrast in cosmo
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 6k
- Forks
- 458
- Avg merge
- 1d 9h
- Merged PRs (30d)
- 41
Description
I have:
- searched the issue tracker for similar issues
- installed the latest version of Quarto CLI
- formatted my issue following the Bug Reports guide
Bug description
The body-secondary mixin, which colors blockquotes, figure/table captions, header section numbers, and margin/aside text, derives its color as theme-dim($body-color, 25%) with no contrast check:
For theme: cosmo this yields #747a7f on #ffffff = 4.34:1, below the WCAG 2.0 AA (1.4.3) minimum of 4.5:1 — axe-core flags it as color-contrast, impact serious. On quarto.org (a cosmo-derived theme with $body-color: #343a40) the same derivation yields #6d7a86 = 4.39:1, which is how this surfaced in an axe audit of the site.
All five @include body-secondary sites are affected (_bootstrap-rules.scss lines 663, 695, 702, 710, 913), e.g. the blockquote rule:
Quarto already has contrast-guarding machinery — theme-contrast() / accessibleContrast() with an explicit "AA" (4.5:1) level — used for navbar, footer, sidebar, and button foregrounds:
Routing the mixin's fallback through it, e.g. theme-contrast(theme-dim($body-color, 25%), $body-bg, "AA"), would keep the dimmed look while guaranteeing conformance for every theme.
Two notes:
- The mixin already honors a
$body-secondarySCSS variable when defined — quarto.org uses that as a workaround (quarto-dev/quarto-web#2102). It appears to be undocumented; worth documenting regardless of the fix here. - Not every built-in theme fails: the
defaulttheme's body color dims to#5a6570= 5.95:1, which passes. The failure depends on where$body-colorlands, which is exactly why a contrast guard rather than a per-theme tweak seems right.
Related: the axe-finding family in #14373 and the accessibility epic #8706.
Investigated with AI assistance grounded in a local clone of quarto-cli (per CONTRIBUTING.md, "Using AI tools to investigate").
Steps to reproduce
---
title: repro
format:
html:
theme: cosmo
axe:
output: document
---
> A blockquote.
Render, open in a browser.
Actual behavior
The blockquote text renders at #747a7f on #ffffff = 4.34:1. axe-core reports:
Serious · WCAG 2.0 AA (1.4.3): Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
Elements must meet minimum color contrast ratio thresholds
p
The same color applies to figcaption/caption/.table-caption, .header-section-number, and margin/aside text.
Expected behavior
Text colors derived by Quarto for built-in themes meet the WCAG AA 4.5:1 minimum, e.g. by passing the body-secondary fallback through the existing theme-contrast(..., "AA") machinery.
Your environment
- IDE: Positron 2026.07.0 (build 352)
- OS: macOS 26.5.1 (build 25F80)
Quarto check output
Quarto 1.10.12
[✓] Checking environment information...
Quarto cache location: /Users/charlottewickham/Library/Caches/quarto
[✓] Checking versions of quarto binary dependencies...
Pandoc version 3.8.3: OK
Dart Sass version 1.87.0: OK
Deno version 2.7.14: OK
Typst version 0.14.2: OK
[✓] Checking versions of quarto dependencies......OK
[✓] Checking Quarto installation......OK
Version: 1.10.12
Path: /Applications/quarto/bin
[✓] Checking tools....................OK
TinyTeX: v2026.04
Chrome Headless Shell: 150.0.7871.115
VeraPDF: 1.28.2
[✓] Checking LaTeX....................OK
Using: TinyTex
Path: /Users/charlottewickham/Library/TinyTeX/bin/universal-darwin
Version: 2026
[✓] Checking Chrome Headless....................OK
Using: Chrome Headless Shell installed by Quarto
Path: /Users/charlottewickham/Library/Application Support/quarto/chrome-headless-shell/chrome-headless-shell-mac-arm64/chrome-headless-shell
Version: 150.0.7871.115
[✓] Checking basic markdown render....OK
[✓] Checking R installation...........OK
Version: 4.6.0
Path: /Library/Frameworks/R.framework/Versions/4.6/Resources
LibPaths:
- /Users/charlottewickham/Library/R/arm64/4.6/library
- /Library/Frameworks/R.framework/Versions/4.6/Resources/library
knitr: 1.51
rmarkdown: 2.31
[✓] Checking Knitr engine render......OK
[✓] Checking Python 3 installation....OK
Version: 3.12.2
Path: /Users/charlottewickham/.pyenv/versions/3.12.2/bin/python3
Jupyter: 5.9.1
Kernels: python3
[✓] Checking Jupyter engine render....OK
[✓] Checking Julia installation...
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with src/resources/formats/html/bootstrap/_bootstrap-mixins.scss and the five body-secondary sites in _bootstrap-rules.scss. Read theme-contrast() and accessibleContrast() in _bootstrap-functions.scss, then reproduce the cosmo example with axe enabled. Done means the affected secondary text styles meet the WCAG AA 4.5:1 contrast threshold across themes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- scss
- Domain
- accessibility, frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100