I have:
Bug description
On a website page that uses an about: template, the about chrome — the title
block (#title-block-header), the profile image, and the links — is rendered
outside the page's <main> landmark. This produces three axe-core
violations on every built-in about template (jolla, trestles, marquee,
solana, broadside):
landmark-no-duplicate-banner — #title-block-header is a <header> that is
no longer nested in <main>, so it implicitly becomes a second banner
landmark alongside the navbar's #quarto-header.
landmark-unique — the two banners have no distinguishing accessible name.
region — the image and links sit outside every landmark.
An otherwise identical page with no about: has none of these: there the title
block renders inside <main> (so it is not a banner), and there is no stray
image/links.
This is related to #14375 / #14376 / #14377, but a distinct code path: those
arise from a listing page with title-block-banner: true, whereas this comes
from the about post-processor re-emitting the title block as a sibling of
<main>. The element targets (.about-image / .about-links) are not the ones
listed in #14377.
I traced the cause to the about post-processor and the EJS templates. It lifts
#title-block-header out of the DOM and captures <main class="content"> as a
string, then each template emits the title (a <header>), the image, and the
links as siblings of <main> inside a plain <div class="quarto-about-*">:
- post-processor:
|
const aboutPagePostProcessor = ( |
|
aboutPage: AboutPage, |
|
pipeline: MarkdownPipeline, |
|
) => { |
|
return ( |
|
doc: Document, |
|
): Promise<HtmlPostProcessResult> => { |
|
// Grab the title and remove it. |
|
const titleEl = doc.getElementById("title-block-header"); |
|
titleEl?.remove(); |
|
const title = titleEl?.outerHTML || ""; |
|
|
|
// Grab the about element |
|
let aboutEl = aboutPage.id ? doc.getElementById(aboutPage.id) : undefined; |
|
if (!aboutEl) { |
|
aboutEl = doc.querySelector("main.content"); |
|
} |
|
|
|
const body = aboutEl?.outerHTML || ""; |
|
const ejsData: AboutPageEjsData = { |
|
title, |
|
body, |
|
image: aboutPage.image, |
|
[kImageAlt]: aboutPage[kImageAlt], |
|
[kImageTitle]: aboutPage[kImageTitle], |
|
links: aboutPage.links, |
|
options: aboutPage.options, |
|
}; |
|
|
|
// Render the template |
|
const aboutPageHtml = renderEjs( |
|
aboutPage.template, |
|
{ about: ejsData }, |
|
true, |
|
!aboutPage.custom && !quartoConfig.isDebug(), |
|
); |
|
|
|
// Replace the about page contents with the updated contents |
|
const aboutPageContainer = doc.createElement("div"); |
|
aboutPageContainer.innerHTML = aboutPageHtml; |
|
aboutEl?.after(...aboutPageContainer.childNodes); |
|
aboutEl?.remove(); |
|
|
|
const result: HtmlPostProcessResult = { |
|
resources: [], |
|
supporting: [], |
|
}; |
|
if (aboutPage.image) { |
|
result.resources.push(aboutPage.image); |
|
} |
|
|
|
// Update any rendered items |
|
pipeline.processRenderedMarkdown(doc); |
|
|
|
return Promise.resolve(result); |
|
}; |
|
}; |
- templates: https://github.com/quarto-dev/quarto-cli/tree/e768e5c2d34381173aa3d43d8d3a332125647561/src/resources/projects/website/about
Investigation was AI-assisted and grounded in a local clone of quarto-cli
(per CONTRIBUTING.md, "Using AI tools to investigate").
Steps to reproduce
Full reproducible website (one page per template + a control):
https://github.com/cwickham/quarto-about-template-a11y — quarto preview
and open any page to see the axe report overlay.
Minimal version — a two-file website project (the navbar supplies the first
banner, so a website project is needed to surface landmark-no-duplicate-banner):
_quarto.yml
project:
type: website
website:
navbar:
right:
- text: Home
href: index.qmd
format:
html:
axe:
output: document
index.qmd
---
title: "Alicia"
subtitle: "Data Scientist"
image: profile.jpg
image-alt: "A descriptive alt text"
about:
template: jolla
links:
- icon: github
text: Github
href: https://github.com
---
A little bit about me.
Then quarto preview and open the page. Swapping template: to trestles,
marquee, solana, or broadside reproduces the same three violations.
Actual behavior
All five about templates emit the title block, image, and links outside
<main>, producing three violations each:
| Template |
landmark-no-duplicate-banner |
landmark-unique |
region |
| (no about) |
— |
— |
— |
| jolla |
✗ |
✗ |
img, .about-links |
| trestles |
✗ |
✗ |
img, .about-links |
| marquee |
✗ |
✗ |
.about-image-container, .about-footer |
| solana |
✗ |
✗ |
.about-links, img |
| broadside |
✗ |
✗ |
.about-links (image is a CSS background) |
The page body itself stays inside <main> on every template — only the title
block, image, and links are stranded outside it.
Expected behavior
The about page's title block, image, and links are page-specific primary
content, not site chrome. They should be contained within the page's single
<main> landmark, and the navbar should be the only banner — matching
the structure of a normal (non-about) Quarto page, where #title-block-header
already renders inside <main>. With that, none of the three violations fire.
Your environment
- IDE: n/a — reproduced with the Quarto CLI directly from the terminal (editor: Positron)
- OS: macOS 26.5.1 (build 25F80)
Quarto check output
Quarto 1.10.8
[✓] 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.8
Path: /Applications/quarto/bin
[✓] Checking tools....................OK
TinyTeX: v2026.04
VeraPDF: 1.28.2
Chrome Headless Shell: (not installed)
[✓] Checking LaTeX....................OK
Using: TinyTex
Path: /Users/charlottewickham/Library/TinyTeX/bin/universal-darwin
Version: 2026
[✓] Checking Chrome Headless....................OK
Using: Chrome found on system
Path: /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
Source: MacOS known location
[✓] Checking basic markdown render....OK
[✓] Checking R installation...........OK
Version: 4.6.0
knitr: 1.51
rmarkdown: 2.31
[✓] Checking Knitr engine render......OK
[✓] Checking Python 3 installation....OK
Version: 3.12.2
Jupyter: 5.9.1
Kernels: python3
[✓] Checking Jupyter engine render....OK
[✓] Checking Julia installation.......OK
I have:
Bug description
On a website page that uses an
about:template, the about chrome — the titleblock (
#title-block-header), the profile image, and the links — is renderedoutside the page's
<main>landmark. This produces three axe-coreviolations on every built-in
abouttemplate (jolla,trestles,marquee,solana,broadside):landmark-no-duplicate-banner—#title-block-headeris a<header>that isno longer nested in
<main>, so it implicitly becomes a secondbannerlandmark alongside the navbar's
#quarto-header.landmark-unique— the two banners have no distinguishing accessible name.region— the image and links sit outside every landmark.An otherwise identical page with no
about:has none of these: there the titleblock renders inside
<main>(so it is not a banner), and there is no strayimage/links.
This is related to #14375 / #14376 / #14377, but a distinct code path: those
arise from a listing page with
title-block-banner: true, whereas this comesfrom the about post-processor re-emitting the title block as a sibling of
<main>. The element targets (.about-image/.about-links) are not the oneslisted in #14377.
I traced the cause to the about post-processor and the EJS templates. It lifts
#title-block-headerout of the DOM and captures<main class="content">as astring, then each template emits the title (a
<header>), the image, and thelinks as siblings of
<main>inside a plain<div class="quarto-about-*">:quarto-cli/src/project/types/website/about/website-about.ts
Lines 301 to 357 in e768e5c
Steps to reproduce
Full reproducible website (one page per template + a control):
https://github.com/cwickham/quarto-about-template-a11y —
quarto previewand open any page to see the axe report overlay.
Minimal version — a two-file website project (the navbar supplies the first
banner, so a website project is needed to surface
landmark-no-duplicate-banner):_quarto.ymlindex.qmdThen
quarto previewand open the page. Swappingtemplate:totrestles,marquee,solana, orbroadsidereproduces the same three violations.Actual behavior
All five
abouttemplates emit the title block, image, and links outside<main>, producing three violations each:landmark-no-duplicate-bannerlandmark-uniqueregionimg,.about-linksimg,.about-links.about-image-container,.about-footer.about-links,img.about-links(image is a CSS background)The page body itself stays inside
<main>on every template — only the titleblock, image, and links are stranded outside it.
Expected behavior
The about page's title block, image, and links are page-specific primary
content, not site chrome. They should be contained within the page's single
<main>landmark, and the navbar should be the onlybanner— matchingthe structure of a normal (non-about) Quarto page, where
#title-block-headeralready renders inside
<main>. With that, none of the three violations fire.Your environment
Quarto check output
Quarto 1.10.8 [✓] 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.8 Path: /Applications/quarto/bin [✓] Checking tools....................OK TinyTeX: v2026.04 VeraPDF: 1.28.2 Chrome Headless Shell: (not installed) [✓] Checking LaTeX....................OK Using: TinyTex Path: /Users/charlottewickham/Library/TinyTeX/bin/universal-darwin Version: 2026 [✓] Checking Chrome Headless....................OK Using: Chrome found on system Path: /Applications/Google Chrome.app/Contents/MacOS/Google Chrome Source: MacOS known location [✓] Checking basic markdown render....OK [✓] Checking R installation...........OK Version: 4.6.0 knitr: 1.51 rmarkdown: 2.31 [✓] Checking Knitr engine render......OK [✓] Checking Python 3 installation....OK Version: 3.12.2 Jupyter: 5.9.1 Kernels: python3 [✓] Checking Jupyter engine render....OK [✓] Checking Julia installation.......OK