MDX Notes
Make your MDX docs accessible to everyone — semantic HTML, ARIA, keyboard nav, screen readers, color contrast, and WCAG compliance made practical.
If someone can't read your docs, your docs don't exist for them. Accessibility isn't a nice-to-have — it's part of the job.
The good news: MDX gives you both Markdown's semantic defaults and React's component model. Together, they make accessible docs pretty straightforward if you think about it from the start.
Why Accessibility Matters
- 15% of people worldwide have some form of disability
- It's the law in many places (ADA, Section 508, EAA)
- It helps everyone — good accessibility means better UX for all users (try using your site with a broken mouse hand)
- SEO bonus — accessible content is well-structured content, and search engines love structure
Semantic HTML
Markdown already produces semantic HTML. That's a free win. Don't throw it away.
A <div> styled to look like a heading fools sighted users but leaves screen reader users completely lost.
Semantic Component Design
ARIA Labels and Roles
When plain HTML isn't enough to communicate meaning, ARIA fills the gaps:
export function CodePlayground({ code, language, title }) {
return (
<div
role="region"
aria-label={`Interactive ${language} code example: ${title}`}
>
<div role="toolbar" aria-label="Code editor controls">
<button aria-label="Copy code to clipboard">
<CopyIcon aria-hidden="true" />
<span className="sr-only">Copy</span>
</button>
<button aria-label="Run code example">
<PlayIcon aria-hidden="true" />
<span className="sr-only">Run</span>
</button>
</div>
<pre role="code" aria-label={`${language} source code`}>
<code>{code}</code>
</pre>
<div
role="log"
aria-label="Code execution output"
aria-live="polite"
>
{/* Output appears here */}
</div>
</div>
);
}ARIA Best Practices
| Rule | Example |
|---|---|
| Use semantic HTML first | <nav> instead of <div role="navigation"> |
| Don't override native semantics | Never put role="button" on a <button> |
| All interactive elements need labels | aria-label or visible text |
| Decorative elements are hidden | aria-hidden="true" on icons with text |
| Live regions announce changes | aria-live="polite" for dynamic updates |
Color Contrast
Your beautiful low-contrast gray-on-slightly-less-gray design? Unreadable for a lot of people. Check your ratios.
// ✅ High contrast color combinations
const badgeStyles = {
info: {
backgroundColor: '#dbeafe', // Light blue background
color: '#1e3a5f', // Dark blue text — 7.2:1 ratio
borderColor: '#3b82f6'
},
warning: {
backgroundColor: '#fef3c7', // Light yellow background
color: '#92400e', // Dark amber text — 5.8:1 ratio
borderColor: '#f59e0b'
},
error: {
backgroundColor: '#fee2e2', // Light red background
color: '#991b1b', // Dark red text — 7.1:1 ratio
borderColor: '#ef4444'
}
};
// WCAG requirements:
// - Normal text: 4.5:1 minimum contrast ratio
// - Large text (18px+ or 14px+ bold): 3:1 minimum
// - UI components: 3:1 minimum against adjacent colorsColor Guidelines
- Never use color alone to convey meaning — add icons, text, or patterns too
- Test with colorblindness simulators — 8% of males are colorblind
- Your dark mode needs good contrast too — don't just invert and call it done
- Use tools: WebAIM Contrast Checker, Chrome DevTools accessibility audit
Keyboard Navigation
If you can't tab to it, click it, or escape from it with just a keyboard — it's broken.
Keyboard Navigation Requirements
- Tab: Move between focusable elements
- Enter/Space: Activate buttons and links
- Arrow keys: Navigate within widget groups (tabs, menus)
- Escape: Close modals, dismiss popups
- Visible focus indicator: Always show where focus is
Screen Reader Compatibility
Screen readers read your page linearly. Write content that makes sense when read aloud, in order.
Screen Reader Tips
- Announce dynamic changes with
aria-liveregions - Hide decorative content with
aria-hidden="true" - Use visually-hidden text for additional context (
.sr-onlyclass) - Test with actual screen readers: NVDA (Windows), VoiceOver (macOS), JAWS
Alt Text for Images
Don't write "image of..." — the screen reader already says "image." Describe what it *shows*.
Focus Management
When content changes dynamically (modals opening, tabs switching), focus needs to follow:
Accessible MDX Components Library
Build a small library of accessible components and reuse them everywhere:
export { Callout } from './Callout'; // role="note" or role="alert"
export { Tabs } from './Tabs'; // Full keyboard + ARIA tabs
export { Accordion } from './Accordion'; // Expandable sections
export { Modal } from './Modal'; // Focus trap + escape handling
export { CodeBlock } from './CodeBlock'; // Labeled code regions
export { SkipLink } from './SkipLink'; // Skip navigation
export { VisuallyHidden } from './Hidden'; // Screen reader only textWCAG Guidelines Compliance
Target WCAG 2.1 Level AA as your minimum. Here's the framework:
The Four Principles (POUR)
- Perceivable — Content can be perceived by all senses
- Operable — Interface works with all input methods
- Understandable — Content and UI behavior make sense
- Solid — Content works with current and future tech
Key Success Criteria
| Criterion | Level | What it means for MDX |
|---|---|---|
| 1.1.1 Non-text Content | A | Alt text on all images |
| 1.3.1 Info and Relationships | A | Semantic HTML from Markdown |
| 1.4.3 Contrast (Minimum) | AA | 4.5:1 for text in components |
| 2.1.1 Keyboard | A | All components keyboard-operable |
| 2.4.6 Headings and Labels | AA | Descriptive heading hierarchy |
| 3.1.1 Language of Page | A | lang attribute on <html> |
| 4.1.2 Name, Role, Value | A | ARIA on custom components |
Testing Tools
Don't guess — test.
# Automated testing
npm install --save-dev axe-core @axe-core/react jest-axe
# Linting
npm install --save-dev eslint-plugin-jsx-a11yRecommended Testing Tools
- axe DevTools — Browser extension for automated audits
- Lighthouse — Built into Chrome DevTools
- WAVE — Web accessibility evaluation tool
- NVDA/VoiceOver — Real screen reader testing (automated tools catch ~30% of issues; real testing catches the rest)
- Stark — Figma/browser contrast checking
- jest-axe — Automated testing in CI/CD
Summary
Accessibility isn't extra work bolted on at the end. It's a quality bar. Markdown gives you semantic HTML for free. Build your custom components with ARIA and keyboard support from day one. Test with real screen readers, not just automated tools. And target WCAG 2.1 AA — your future self navigating with a broken trackpad will thank you.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Accessibility in MDX.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this MDX Tutorial topic.
Search Terms
mdx-tutorial, mdx tutorial, mdx, tutorial, best, practices, accessibility, accessibility in mdx
Related MDX Tutorial Topics