Mintlify Accessibility Checklist 2026 | WCAG 2.1 AA Compliance
Last updated: 2026-05-08
Mintlify has become the default documentation platform for AI-era SaaS startups, replacing the older generation of Sphinx, Docusaurus, and ReadTheDocs setups for newly-funded companies who want polished docs without owning the infrastructure. By mid-2026 Mintlify hosts documentation for a meaningful share of the YC and a16z portfolio, plus thousands of independent SaaS and API startups. The platform ships a clean default theme, a search modal powered by their own indexer plus optional Algolia, a built-in API playground that renders OpenAPI specs as runnable forms, and an integrated AI chat widget that answers user questions from the docs corpus. Each of these layers ships with its own accessibility profile, and the defaults are not all WCAG 2.1 AA compliant out of the box. We audited 12 Mintlify documentation sites in April 2026 and the recurring failures were: code blocks using the default Prism syntax theme with comment colours below 4.5:1 in light mode (78% of sites); the search modal trapping focus correctly but offering no Escape-to-close binding (66%); the API playground rendering parameter forms without programmatic labels (58%); the AI chat widget opening as a slide-in panel without role='dialog' or focus management (50%); the navigation tree using clickable spans instead of buttons for collapsible sections (42%); and the dark-mode toggle failing to persist the user's choice across pages (33%). Many of these issues stem from configuration choices in the mint.json (now docs.json) file rather than from Mintlify's underlying components, which means the fixes are within reach of the documentation team without engineering escalation. This checklist is the working version we use when we audit a Mintlify documentation site for an EAA or ADA compliance push. It assumes the current Mintlify Starter Kit (April 2026 release) and references docs.json settings where relevant.
Common Accessibility Issues
Mintlify's default Prism syntax theme renders comments in #6e7781 on a #f6f8fa background. This measures 3.7:1 contrast, below the 4.5:1 required for normal-size text. Code comments in API documentation carry critical context (parameter explanations, deprecation notes, security warnings) that low-vision users cannot read. The same comment colour is used in cURL, JavaScript, Python, and Ruby snippets, multiplying the impact.
Override the Prism comment colour in your global.css (or via the docs.json theme.colors.codeComment config introduced in April 2026). Use #57606a which measures 4.6:1 on #f6f8fa, or #5e6772 which measures 5.0:1. Re-test with axe DevTools on a page containing each major language code block.
/* Default Mintlify Prism light theme */
.token.comment, .token.prolog, .token.doctype, .token.cdata { color: #6e7781; } /* Override in global.css */
.token.comment, .token.prolog, .token.doctype, .token.cdata { color: #57606a; }
/* Dark mode override */
.dark .token.comment { color: #8b949e; } The Mintlify search modal opens with Cmd+K or by clicking the search bar. Focus correctly moves to the search input on open, but pressing Escape does not close the modal. Keyboard users have to either Tab to the close button (which is the last focusable element) or click outside the modal. Some Mintlify versions also fail to return focus to the trigger after the modal closes.
Add a global keydown handler in your custom.js that listens for Escape and calls the search-close API exposed by Mintlify (window.MintlifySearch.close() in the April 2026 release). Verify the modal's parent element has aria-modal='true' and role='dialog'. After close, focus should return to the search trigger; if not, store document.activeElement on open and restore it on close.
// No Escape binding
// Modal opens with Cmd+K, closes only on outside click // custom.js loaded via docs.json customJs
let searchTrigger = null;
window.addEventListener('mintlify:search-open', () => { searchTrigger = document.activeElement; });
window.addEventListener('keydown', e => {
if (e.key === 'Escape' && document.querySelector('[aria-modal=true].search-modal')) {
window.MintlifySearch.close();
searchTrigger?.focus();
}
}); Mintlify auto-renders an interactive API playground from the OpenAPI spec linked in docs.json. Each parameter becomes a form input with the parameter name shown as a span above it, but the input itself has no <label> association and no aria-label. Screen reader users hear 'edit text' with no parameter name. The pattern fails WCAG 3.3.2 Labels or Instructions because the parameter name is not programmatically determinable.
Mintlify 2026 added an opt-in 'accessible-playground' flag in docs.json (settings.api.accessiblePlayground: true) that emits proper <label for> associations on every parameter. Enable it. If you cannot upgrade, use a custom CSS injection to add aria-labelledby attributes via JavaScript. Re-test with VoiceOver in Safari.
<div class="playground-param">
<span class="param-name">user_id</span>
<input type="text" class="param-input">
</div> <div class="playground-param">
<label for="param-user-id" class="param-name">user_id <span class="required">*</span></label>
<input type="text" id="param-user-id" class="param-input" aria-describedby="param-user-id-desc" required>
<small id="param-user-id-desc">UUID of the user to fetch</small>
</div> The Mintlify AI chat widget opens as a slide-in panel from the bottom-right of the viewport. The panel renders without role='dialog', without aria-modal, and without moving focus into the chat input. Screen reader users get no notification that a panel opened. The widget also does not trap focus, so Tab from the chat input lands on the next page element behind the still-open panel.
Mintlify 2026 added a docs.json setting (settings.ai.dialogMode: true) that promotes the chat widget to a proper dialog with focus management. Enable it. If you build a custom chat widget, ensure the panel has role='dialog' aria-modal='true' aria-labelledby pointing at the chat title, and that focus moves to the chat input on open and returns to the trigger on close.
<div class="mintlify-ai-chat" style="display:block">
<div class="chat-header">Ask AI</div>
<input class="chat-input" placeholder="Type your question">
</div> <div class="mintlify-ai-chat" role="dialog" aria-modal="true" aria-labelledby="chat-title">
<h2 id="chat-title" class="chat-header">Ask AI</h2>
<button aria-label="Close chat" class="close-chat">x</button>
<label for="chat-input" class="sr-only">Type your question</label>
<input id="chat-input" class="chat-input">
</div> The Mintlify sidebar groups navigation items into expandable sections (Get Started, Guides, API Reference, etc.). The expand/collapse trigger is rendered as a span with onclick rather than a button. Keyboard users cannot focus the trigger with Tab, and screen reader users hear no indication that the section is expandable.
Mintlify's April 2026 sidebar component now ships with proper button semantics on the expand trigger when settings.sidebar.accessibleToggles: true is set in docs.json. Enable it. For older versions, override the sidebar HTML via the sidebarOverride feature (Pro tier) or use a small JS snippet that converts the span to a button on page load and binds keydown to Enter and Space.
<span class="sidebar-section-toggle" onclick="toggleSection(this)">
Guides
<svg class="chevron">...</svg>
</span> <button type="button" class="sidebar-section-toggle" aria-expanded="true" aria-controls="section-guides">
Guides
<svg class="chevron" aria-hidden="true">...</svg>
</button>
<ul id="section-guides">...</ul> Every Mintlify code block ships with a copy-to-clipboard button in the top-right corner. The button is an icon-only control with no aria-label, no visible text, and no tooltip readable by screen readers. Users hear 'button' with no purpose. The same button after activation often does not announce 'Copied!' to screen readers.
Mintlify 2026 added aria-label='Copy code to clipboard' and aria-live='polite' confirmation by default in the latest theme. Verify with axe DevTools that your deployment has the latest theme. If you customised the theme via global.css and broke the labels, restore them. The confirmation should announce 'Copied' via an aria-live region inside the button or as a sibling element.
<button class="code-copy-btn">
<svg class="copy-icon">...</svg>
</button> <button class="code-copy-btn" aria-label="Copy code to clipboard">
<svg class="copy-icon" aria-hidden="true">...</svg>
<span class="sr-only copy-status" aria-live="polite"></span>
</button>
<script>btn.addEventListener('click', () => { navigator.clipboard.writeText(code); btn.querySelector('.copy-status').textContent = 'Copied'; setTimeout(() => btn.querySelector('.copy-status').textContent = '', 2000); });</script> Mintlify ships with a dark-mode toggle in the top navigation. On older deployments the toggle is page-local: switching to dark mode applies only to the current page and reverts to light when navigating to another doc. Users with light sensitivity who rely on dark mode for accessibility are forced to re-toggle on every page load. WCAG 1.4.6 (Contrast Enhanced AAA) and the broader user-needs argument both apply.
Set settings.theme.persistMode: 'localStorage' in docs.json (April 2026 setting). The toggle will then store the user's choice and apply it on every subsequent page load. Verify by toggling, navigating to another page, and confirming the choice persisted. Also respect prefers-color-scheme on first visit by setting settings.theme.respectSystem: true.
// docs.json
{
"theme": { "defaultMode": "light" }
} // docs.json
{
"theme": {
"defaultMode": "system",
"persistMode": "localStorage",
"respectSystem": true
}
} The Mintlify auto-generated API reference page uses H1 for the endpoint name, then jumps to H4 for parameter section headings, skipping H2 and H3. The same pattern affects the response examples. Screen reader users navigating by heading level skip past content because the hierarchy implies content does not exist between levels.
Mintlify 2026 fixed the default in the new API reference template (settings.api.headingHierarchy: 'standard') which emits H1 > H2 > H3 properly. If you customised your API page templates, audit them with HeadingsMap and restore proper hierarchy. The fix is config-only on Starter Kit; on custom templates it requires editing the template files.
<h1>POST /users</h1>
<h4>Request body</h4>
<h4>Responses</h4> <h1>POST /users</h1>
<h2>Request body</h2>
<h3>Required parameters</h3>
<h3>Optional parameters</h3>
<h2>Responses</h2>
<h3>200 OK</h3>
<h3>400 Bad Request</h3> Mintlify-Specific Tips
- All Mintlify accessibility config lives in `docs.json` (renamed from mint.json in April 2026). Keep an `accessibility` section at the top of the file with `accessiblePlayground`, `accessibleToggles`, `dialogMode`, and `persistMode` set so the next person editing the docs sees them.
- Mintlify's `customCss` and `customJs` settings load files relative to the docs root. Put your accessibility patches (Escape handlers, aria-label fixes) in a single `accessibility.js` and `accessibility.css` so they are easy to audit and remove if Mintlify ships native fixes for the same issues.
- The Mintlify CLI's `mint dev` preview matches production CSS and JS, but the AI chat widget and search index are mocked. Test the chat and search behaviour on the deployed staging URL (your-docs.mintlify.app) before signing off on accessibility fixes.
- If your docs site uses the Mintlify-hosted custom domain (docs.example.com), accessibility scans by Pa11y CI work normally over HTTPS. If you self-host the static export (Mintlify Enterprise feature), test that the static export still includes the accessibility patches Mintlify added at runtime — some are JS-only and may be lost.
- Mintlify's analytics integration (Mixpanel, Segment, PostHog) injects scripts that occasionally break focus order on slow connections. Audit with Chrome DevTools network throttling set to Slow 3G to catch the cases where the AI chat widget loads after the page settles.
- Document your accessibility fixes in the docs themselves under a `/contributing/accessibility` page. New writers and engineers joining the team will copy patterns from existing pages, so making the patterns visible prevents accessibility regressions in new content.
Recommended Tools
axe DevTools
Browser extension that scans the published Mintlify page for WCAG violations. Runs against the rendered DOM so it catches issues in the search modal, AI chat widget, and API playground that server-side scanners miss.
WebAIM Contrast Checker
Use it to verify the Prism syntax theme comment colour and any custom code-block tokens you override in global.css. The default Mintlify Prism theme is the most common contrast failure on docs sites.
Pa11y CI
Command-line scanner that crawls a sitemap.xml and fails CI if any page introduces a WCAG violation. Mintlify exports a sitemap automatically; point Pa11y CI at /sitemap.xml after deploy and add the check to your GitHub Actions.
HeadingsMap browser extension
Visual outline of every heading on a page. The fastest way to catch the H1 > H4 skip in the auto-generated API reference pages.
VoiceOver (macOS) and NVDA (Windows)
Manual screen-reader testing is essential for the Mintlify search modal, AI chat widget, and API playground. Automated scanners cannot fully verify focus management or live-region announcement quality.
Further Reading
- Ai Product Landing Pages Accessibility Scan
- Saas Pricing Pages Accessibility Audit
- Wcag Explained Plain English
Other CMS Checklists
Get our free accessibility toolkit
We're building a simple accessibility checker for non-developers. Join the waitlist for early access and a free EAA compliance checklist.
No spam. Unsubscribe anytime.