JavaScript display engine for LaTeX, MathML, and AsciiMath mathematical notation in browsers and Node.js
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
MathJax provides comprehensive accessibility support including speech generation, semantic enrichment, interactive exploration, and assistive technology integration to make mathematical content accessible to users with disabilities.
Generate spoken descriptions of mathematical expressions for screen readers and voice output.
interface AccessibilityOptions {
/** Background color for highlighting */
backgroundColor?: string;
/** Background opacity (0-1) */
backgroundOpacity?: number;
/** Foreground color for highlighting */
foregroundColor?: string;
/** Foreground opacity (0-1) */
foregroundOpacity?: number;
/** Highlight color scheme */
highlight?: 'None' | 'Hover' | 'Flame' | 'Blue' | 'Green' | 'Magenta' | 'Red';
/** Enable subtitles display */
subtitles?: boolean;
/** Enable speech output */
speech?: boolean;
}Usage Examples:
// Enable accessibility features
MathJax.config.options = {
enableAssistiveMml: true,
enableExplorer: true,
a11y: {
backgroundColor: 'Blue',
backgroundOpacity: 0.2,
foregroundColor: 'Yellow',
foregroundOpacity: 1,
highlight: 'Flame',
subtitles: true,
speech: true
}
};
// Load accessibility components
MathJax.config.loader.load.push(
'a11y/semantic-enrich',
'a11y/speech',
'a11y/explorer',
'a11y/assistive-mml'
);Enhance mathematical expressions with semantic information for better accessibility.
// Semantic enrichment is automatically applied when accessibility is enabled
// No direct API calls needed - works transparently with input processorsConfiguration Examples:
// Configure semantic enrichment
MathJax.config.options = {
enableAssistiveMml: true, // Enable assistive MathML generation
sre: {
domain: 'mathspeak', // Speech domain
style: 'default', // Speech style
locale: 'en', // Language locale
modality: 'speech' // Output modality
}
};
// Advanced semantic options
MathJax.config.sre = {
json: '/path/to/mathmaps', // Path to semantic rules
xpath: '/path/to/xpath', // XPath evaluator
domain: 'clearspeak', // Alternative speech domain
style: 'brief' // Brief speech style
};Provide interactive navigation and exploration of mathematical expressions.
// Explorer is activated automatically when enabled
// Users can navigate using keyboard shortcuts:
// - Arrow keys: Navigate expression tree
// - Enter: Speak current sub-expression
// - Escape: Exit exploration modeConfiguration Examples:
// Enable interactive explorer
MathJax.config.options = {
enableExplorer: true,
a11y: {
keyMagnifier: true, // Magnify focused elements
speechTags: true, // Include speech tags
braille: false // Braille output (experimental)
}
};
// Explorer keyboard shortcuts
const explorerKeys = {
'ArrowRight': 'next sibling',
'ArrowLeft': 'previous sibling',
'ArrowDown': 'first child',
'ArrowUp': 'parent',
'Enter': 'speak current',
'Escape': 'exit explorer'
};Generate enhanced MathML with accessibility attributes for assistive technologies.
// Assistive MathML is generated automatically when enabled
// Adds aria-label, role, and other accessibility attributesExamples:
// Enable assistive MathML
MathJax.config.options = {
enableAssistiveMml: true
};
// Result includes accessibility attributes:
// <math aria-label="x squared plus y squared equals z squared" role="img">
// <mrow>
// <msup aria-label="x squared">
// <mi>x</mi>
// <mn>2</mn>
// </msup>
// <mo>+</mo>
// <msup aria-label="y squared">
// <mi>y</mi>
// <mn>2</mn>
// </msup>
// <mo>=</mo>
// <msup aria-label="z squared">
// <mi>z</mi>
// <mn>2</mn>
// </msup>
// </mrow>
// </math>The Speech Rule Engine provides the core functionality for semantic analysis and speech generation.
// SRE is loaded automatically with accessibility features
MathJax.config.loader.load.push('a11y/sre');
// SRE provides multiple speech domains:
// - mathspeak: MathSpeak standard
// - clearspeak: ClearSpeak standard
// - chromevox: ChromeVox style
// - emacspeak: Emacspeak styleAnalyze mathematical complexity to optimize speech output.
// Load complexity analyzer
MathJax.config.loader.load.push('a11y/complexity');
// Complexity affects speech verbosity
MathJax.config.sre = {
domain: 'clearspeak',
style: 'auto' // Automatically adjust based on complexity
};Provide visual feedback during navigation and exploration.
// Configure visual highlighting
MathJax.config.options = {
a11y: {
backgroundColor: 'Blue',
backgroundOpacity: 0.3,
foregroundColor: 'White',
foregroundOpacity: 1,
highlight: 'Hover' // Highlight on mouse hover
}
};
// Available highlight modes:
// - 'None': No highlighting
// - 'Hover': Highlight on hover
// - 'Flame': Red highlighting
// - 'Blue': Blue highlighting
// - 'Green': Green highlighting
// - 'Magenta': Magenta highlighting
// - 'Red': Red highlightinginterface GlobalAccessibilityOptions {
/** Enable assistive MathML generation */
enableAssistiveMml?: boolean;
/** Enable interactive explorer */
enableExplorer?: boolean;
/** Accessibility-specific options */
a11y?: AccessibilityDisplayOptions;
/** Speech Rule Engine options */
sre?: SREOptions;
}interface AccessibilityDisplayOptions {
/** Background highlight color */
backgroundColor?: string;
/** Background opacity (0-1) */
backgroundOpacity?: number;
/** Foreground highlight color */
foregroundColor?: string;
/** Foreground opacity (0-1) */
foregroundOpacity?: number;
/** Highlight color scheme */
highlight?: 'None' | 'Hover' | 'Flame' | 'Blue' | 'Green' | 'Magenta' | 'Red';
/** Show subtitles */
subtitles?: boolean;
/** Enable speech output */
speech?: boolean;
/** Magnify focused elements */
keyMagnifier?: boolean;
/** Include speech tags in output */
speechTags?: boolean;
/** Enable braille output (experimental) */
braille?: boolean;
}interface SREOptions {
/** Speech domain */
domain?: 'mathspeak' | 'clearspeak' | 'chromevox' | 'emacspeak';
/** Speech style */
style?: 'default' | 'brief' | 'sbrief' | 'auto';
/** Language locale */
locale?: string;
/** Output modality */
modality?: 'speech' | 'braille' | 'prefix' | 'summary';
/** Path to semantic rules */
json?: string;
/** XPath evaluator path */
xpath?: string;
}// Comprehensive accessibility setup
window.MathJax = {
// Load accessibility components
loader: {
load: [
'input/tex', 'output/chtml',
'a11y/semantic-enrich',
'a11y/speech',
'a11y/explorer',
'a11y/complexity',
'a11y/assistive-mml'
]
},
// Enable accessibility features
options: {
enableAssistiveMml: true,
enableExplorer: true,
// Visual highlighting
a11y: {
backgroundColor: 'Blue',
backgroundOpacity: 0.2,
foregroundColor: 'Yellow',
foregroundOpacity: 1,
highlight: 'Hover',
subtitles: true,
speech: true,
keyMagnifier: true,
speechTags: true
},
// Speech configuration
sre: {
domain: 'clearspeak',
style: 'default',
locale: 'en',
modality: 'speech'
}
},
// TeX input with accessibility-friendly packages
tex: {
packages: ['base', 'ams', 'color'],
macros: {
// Define accessible macros
accessible: ['\\text{#1}', 1]
}
},
// CommonHTML output with accessibility
chtml: {
fontURL: 'https://cdn.jsdelivr.net/npm/mathjax@4/fonts/woff-v2',
adaptiveCSS: true
}
};Standard mathematical speech rules from Design Science.
MathJax.config.sre = {
domain: 'mathspeak',
style: 'default' // or 'brief', 'sbrief'
};
// Examples:
// "x^2" → "x squared"
// "\\frac{a}{b}" → "fraction a over b"
// "\\sum_{i=1}^n" → "sum from i equals 1 to n"Mathematical speech rules optimized for clarity.
MathJax.config.sre = {
domain: 'clearspeak',
style: 'default' // or 'brief'
};
// Examples:
// "x^2" → "x squared"
// "\\frac{a}{b}" → "the fraction with numerator a and denominator b"
// "\\sqrt{x}" → "the square root of x"Speech rules optimized for the ChromeVox screen reader.
MathJax.config.sre = {
domain: 'chromevox',
style: 'default'
};Users can navigate mathematical expressions using keyboard shortcuts:
| Key | Action |
|---|---|
→ | Move to next sibling |
← | Move to previous sibling |
↓ | Move to first child |
↑ | Move to parent |
Enter | Speak current element |
Escape | Exit exploration mode |
Space | Toggle subtitles |
// Enable explorer and handle events
MathJax.config.options = {
enableExplorer: true,
a11y: {
subtitles: true,
speech: true
}
};
// Listen for navigation events (if needed for custom handling)
document.addEventListener('click', (event) => {
const mathElement = event.target.closest('.mjx-chtml, .mjx-svg');
if (mathElement) {
// Math element clicked - explorer will activate automatically
console.log('Math explorer activated');
}
});// Optimize for NVDA screen reader
MathJax.config.options = {
enableAssistiveMml: true,
sre: {
domain: 'mathspeak',
style: 'default',
locale: 'en'
}
};// Optimize for JAWS screen reader
MathJax.config.options = {
enableAssistiveMml: true,
sre: {
domain: 'clearspeak',
style: 'brief',
locale: 'en'
}
};// Optimize for VoiceOver (macOS/iOS)
MathJax.config.options = {
enableAssistiveMml: true,
sre: {
domain: 'mathspeak',
style: 'sbrief', // Super brief for VoiceOver
locale: 'en'
}
};// Add custom speech rules (requires SRE knowledge)
MathJax.config.sre = {
domain: 'clearspeak',
style: 'default',
// Custom rules can be added through SRE configuration
customRules: {
'custom-notation': 'custom speech pattern'
}
};// Configure for different languages
MathJax.config.sre = {
domain: 'mathspeak',
style: 'default',
locale: 'es', // Spanish
// Available locales: en, es, fr, de, it, etc.
};
// Language-specific speech patterns
const languageConfigs = {
en: { domain: 'clearspeak', style: 'default' },
es: { domain: 'mathspeak', style: 'default' },
fr: { domain: 'mathspeak', style: 'brief' },
de: { domain: 'mathspeak', style: 'default' }
};
// Apply language configuration
const userLang = navigator.language.substring(0, 2);
MathJax.config.sre = languageConfigs[userLang] || languageConfigs.en;// Enable experimental braille support
MathJax.config.options = {
a11y: {
braille: true
},
sre: {
modality: 'braille',
domain: 'mathspeak'
}
};// Test accessibility features
function testAccessibility() {
// Check if assistive MathML is generated
const mathElements = document.querySelectorAll('[role="img"]');
console.log(`Found ${mathElements.length} accessible math elements`);
// Check aria-labels
mathElements.forEach((element, index) => {
const label = element.getAttribute('aria-label');
console.log(`Element ${index}: ${label || 'No aria-label'}`);
});
// Test speech generation
if (window.SRE) {
const testExpr = 'x^2 + y^2 = z^2';
const speech = window.SRE.toSpeech(testExpr);
console.log(`Speech output: ${speech}`);
}
}
// Run accessibility tests
MathJax.whenReady(testAccessibility);// Simulate screen reader interaction
function simulateScreenReader() {
const mathElements = document.querySelectorAll('.mjx-chtml, .mjx-svg');
mathElements.forEach(element => {
// Check for proper ARIA attributes
const role = element.getAttribute('role');
const label = element.getAttribute('aria-label');
const describedBy = element.getAttribute('aria-describedby');
console.log('Accessibility attributes:', {
role,
label,
describedBy
});
// Test focus management
element.tabIndex = 0;
element.addEventListener('focus', () => {
console.log('Math element focused:', label);
});
});
}
// Apply screen reader simulation
MathJax.typesetPromise().then(simulateScreenReader);// Enable accessibility only when needed
const hasScreenReader = window.navigator.userAgent.includes('NVDA') ||
window.navigator.userAgent.includes('JAWS') ||
window.speechSynthesis;
if (hasScreenReader) {
MathJax.config.options.enableAssistiveMml = true;
MathJax.config.options.enableExplorer = true;
MathJax.config.loader.load.push('a11y/semantic-enrich', 'a11y/speech');
}// Load accessibility features on demand
function enableAccessibility() {
return MathJax.loader.load('a11y/semantic-enrich', 'a11y/speech', 'a11y/explorer')
.then(() => {
MathJax.config.options.enableAssistiveMml = true;
MathJax.config.options.enableExplorer = true;
// Re-process existing math
return MathJax.typesetPromise();
});
}
// Enable on user request or detection
document.getElementById('enable-accessibility').addEventListener('click', enableAccessibility);