0
# Document Rendering
1
2
MathJax provides comprehensive document rendering capabilities for automatically finding, processing, and rendering mathematical expressions within HTML documents, with support for dynamic content updates and performance optimization.
3
4
## Capabilities
5
6
### Document Typesetting
7
8
Process mathematical expressions within HTML documents automatically.
9
10
```javascript { .api }
11
/**
12
* Typeset mathematics in specified elements (synchronous)
13
* @param elements - Elements to process, or null for entire document
14
*/
15
function typeset(elements?: Element[]): void;
16
17
/**
18
* Typeset mathematics in specified elements (asynchronous)
19
* @param elements - Elements to process, or null for entire document
20
* @returns Promise that resolves when typesetting is complete
21
*/
22
function typesetPromise(elements?: Element[]): Promise<void>;
23
24
/**
25
* Clear typeset mathematics from specified elements
26
* @param elements - Elements to clear, or null for entire document
27
*/
28
function typesetClear(elements?: Element[]): void;
29
30
/**
31
* Get completion promise for current operations
32
* @returns Promise that resolves when all operations are complete
33
*/
34
function done(): Promise<void>;
35
36
/**
37
* Execute callback when MathJax is ready
38
* @param callback - Function to execute when ready
39
* @returns Promise that resolves after callback execution
40
*/
41
function whenReady(callback: () => void): Promise<void>;
42
```
43
44
**Usage Examples:**
45
46
```javascript
47
// Typeset entire document
48
MathJax.typeset();
49
50
// Typeset specific elements
51
const elements = document.querySelectorAll('.math-content');
52
MathJax.typeset(Array.from(elements));
53
54
// Asynchronous typesetting
55
await MathJax.typesetPromise();
56
57
// Typeset with callback
58
MathJax.typesetPromise().then(() => {
59
console.log('Typesetting complete');
60
});
61
62
// Clear mathematics from document
63
MathJax.typesetClear();
64
65
// Wait for operations to complete
66
await MathJax.done();
67
68
// Execute when ready
69
MathJax.whenReady(() => {
70
console.log('MathJax is ready');
71
});
72
```
73
74
### Dynamic Content Updates
75
76
Handle dynamically added mathematical content:
77
78
```javascript
79
// Add new math content
80
const newContent = document.createElement('div');
81
newContent.innerHTML = 'The equation is $x^2 + y^2 = z^2$.';
82
document.body.appendChild(newContent);
83
84
// Typeset only the new content
85
MathJax.typeset([newContent]);
86
87
// Or typeset the entire document
88
MathJax.typeset();
89
90
// Handle content updates with promises
91
async function updateMathContent() {
92
// Clear existing math
93
MathJax.typesetClear([targetElement]);
94
95
// Update content
96
targetElement.innerHTML = newMathExpression;
97
98
// Re-typeset
99
await MathJax.typesetPromise([targetElement]);
100
}
101
```
102
103
### Document Processing Control
104
105
Control which elements and content get processed:
106
107
```javascript
108
// Configure processing classes
109
MathJax.config.options = {
110
processHtmlClass: 'tex2jax_process',
111
ignoreHtmlClass: 'tex2jax_ignore',
112
processScriptType: 'math/tex'
113
};
114
115
// Process only specific elements
116
const mathElements = document.querySelectorAll('.contains-math');
117
MathJax.typeset(Array.from(mathElements));
118
119
// Skip specific elements
120
const elementsToSkip = document.querySelectorAll('.skip-math');
121
elementsToSkip.forEach(el => el.classList.add('tex2jax_ignore'));
122
MathJax.typeset();
123
```
124
125
## Document Configuration
126
127
### Startup Options
128
129
```javascript { .api }
130
interface StartupOptions {
131
/** Elements to process on startup */
132
elements?: Element[] | null;
133
/** Auto-typeset on ready */
134
typeset?: boolean;
135
/** Ready callback function */
136
ready?: () => void;
137
/** Page ready callback function */
138
pageReady?: () => void;
139
/** Document or document selector */
140
document?: string | Document;
141
/** Input processors to use */
142
input?: string[];
143
/** Output processor to use */
144
output?: string;
145
/** DOM adaptor to use */
146
adaptor?: string | null;
147
/** Document handler to use */
148
handler?: string | null;
149
}
150
```
151
152
**Configuration Examples:**
153
154
```javascript
155
// Browser configuration
156
window.MathJax = {
157
startup: {
158
elements: null, // Process entire document
159
typeset: true, // Auto-typeset on load
160
ready: () => {
161
console.log('MathJax startup complete');
162
},
163
pageReady: () => {
164
console.log('Page ready for typesetting');
165
}
166
}
167
};
168
169
// Node.js configuration
170
const config = {
171
startup: {
172
typeset: false, // Don't auto-typeset in Node.js
173
document: myDocument,
174
elements: specificElements
175
}
176
};
177
```
178
179
### Processing Options
180
181
```javascript { .api }
182
interface ProcessingOptions {
183
/** Elements to process */
184
elements?: Element[];
185
/** HTML class for processing */
186
processHtmlClass?: string;
187
/** HTML class to ignore */
188
ignoreHtmlClass?: string;
189
/** Script type to process */
190
processScriptType?: string;
191
/** Enable assistive MathML */
192
enableAssistiveMml?: boolean;
193
/** Compile error handler */
194
compileError?: (doc: MathDocument, math: MathItem, error: Error) => void;
195
/** Typeset error handler */
196
typesetError?: (doc: MathDocument, math: MathItem, error: Error) => void;
197
}
198
```
199
200
## Error Handling
201
202
### Processing Errors
203
204
Handle errors during document processing:
205
206
```javascript
207
// Configure error handlers
208
MathJax.config.options = {
209
compileError: (doc, math, error) => {
210
console.error('Compilation error:', error.message);
211
// Display error message in place of math
212
math.typesetRoot.innerHTML = `<span style="color:red">[${error.message}]</span>`;
213
},
214
215
typesetError: (doc, math, error) => {
216
console.error('Typesetting error:', error.message);
217
// Handle typesetting failure
218
math.typesetRoot.innerHTML = '<span style="color:red">[Typeset Error]</span>';
219
}
220
};
221
```
222
223
### Graceful Error Recovery
224
225
```javascript
226
async function safeTypeset(elements) {
227
try {
228
await MathJax.typesetPromise(elements);
229
} catch (error) {
230
console.error('Typesetting failed:', error.message);
231
232
// Fallback: try individual elements
233
if (elements) {
234
for (const element of elements) {
235
try {
236
await MathJax.typesetPromise([element]);
237
} catch (elementError) {
238
console.warn(`Failed to typeset element:`, elementError.message);
239
// Mark element with error class
240
element.classList.add('math-error');
241
}
242
}
243
}
244
}
245
}
246
```
247
248
## Performance Optimization
249
250
### Efficient Document Processing
251
252
```javascript
253
// Process only changed content
254
class MathContentManager {
255
constructor() {
256
this.processedElements = new WeakSet();
257
}
258
259
async updateElement(element) {
260
// Clear if previously processed
261
if (this.processedElements.has(element)) {
262
MathJax.typesetClear([element]);
263
}
264
265
// Process element
266
await MathJax.typesetPromise([element]);
267
this.processedElements.add(element);
268
}
269
270
async updateMultiple(elements) {
271
// Clear all elements first
272
const toProcess = elements.filter(el => this.processedElements.has(el));
273
if (toProcess.length > 0) {
274
MathJax.typesetClear(toProcess);
275
}
276
277
// Process all elements
278
await MathJax.typesetPromise(elements);
279
elements.forEach(el => this.processedElements.add(el));
280
}
281
}
282
```
283
284
### Batch Processing
285
286
```javascript
287
// Batch multiple updates
288
class BatchProcessor {
289
constructor() {
290
this.pendingElements = new Set();
291
this.timeoutId = null;
292
}
293
294
scheduleUpdate(element) {
295
this.pendingElements.add(element);
296
297
// Debounce updates
298
if (this.timeoutId) {
299
clearTimeout(this.timeoutId);
300
}
301
302
this.timeoutId = setTimeout(() => {
303
this.processBatch();
304
}, 100);
305
}
306
307
async processBatch() {
308
if (this.pendingElements.size === 0) return;
309
310
const elements = Array.from(this.pendingElements);
311
this.pendingElements.clear();
312
313
await MathJax.typesetPromise(elements);
314
}
315
}
316
```
317
318
## Advanced Document Processing
319
320
### Custom Math Discovery
321
322
```javascript
323
// Custom math finder
324
function findCustomMath(container) {
325
const mathElements = [];
326
327
// Find custom math delimiters
328
const walker = document.createTreeWalker(
329
container,
330
NodeFilter.SHOW_TEXT,
331
null,
332
false
333
);
334
335
let node;
336
while (node = walker.nextNode()) {
337
if (node.textContent.includes('{{math}}')) {
338
// Process custom math syntax
339
mathElements.push(node.parentElement);
340
}
341
}
342
343
return mathElements;
344
}
345
346
// Process custom math
347
const customMath = findCustomMath(document.body);
348
MathJax.typeset(customMath);
349
```
350
351
### Integration with Frameworks
352
353
#### React Integration
354
355
```javascript
356
import { useEffect, useRef } from 'react';
357
358
function MathComponent({ expression, display = false }) {
359
const mathRef = useRef();
360
361
useEffect(() => {
362
if (mathRef.current && window.MathJax) {
363
// Clear previous content
364
MathJax.typesetClear([mathRef.current]);
365
366
// Set new content
367
mathRef.current.innerHTML = display
368
? `$$${expression}$$`
369
: `$${expression}$`;
370
371
// Typeset new content
372
MathJax.typeset([mathRef.current]);
373
}
374
}, [expression, display]);
375
376
return <div ref={mathRef} />;
377
}
378
```
379
380
#### Vue Integration
381
382
```javascript
383
export default {
384
props: ['expression', 'display'],
385
mounted() {
386
this.renderMath();
387
},
388
updated() {
389
this.renderMath();
390
},
391
methods: {
392
async renderMath() {
393
if (this.$refs.math && window.MathJax) {
394
MathJax.typesetClear([this.$refs.math]);
395
396
const delimiter = this.display ? '$$' : '$';
397
this.$refs.math.innerHTML = `${delimiter}${this.expression}${delimiter}`;
398
399
await MathJax.typesetPromise([this.$refs.math]);
400
}
401
}
402
},
403
template: '<div ref="math"></div>'
404
};
405
```
406
407
### Progressive Enhancement
408
409
```javascript
410
// Progressive enhancement for math content
411
class MathEnhancer {
412
constructor() {
413
this.observer = new MutationObserver(this.handleMutations.bind(this));
414
}
415
416
start() {
417
// Process existing content
418
MathJax.typeset();
419
420
// Watch for new content
421
this.observer.observe(document.body, {
422
childList: true,
423
subtree: true
424
});
425
}
426
427
stop() {
428
this.observer.disconnect();
429
}
430
431
handleMutations(mutations) {
432
const elementsToProcess = new Set();
433
434
mutations.forEach(mutation => {
435
mutation.addedNodes.forEach(node => {
436
if (node.nodeType === Node.ELEMENT_NODE) {
437
// Check if element contains math
438
if (this.containsMath(node)) {
439
elementsToProcess.add(node);
440
}
441
442
// Check child elements
443
const mathElements = node.querySelectorAll('.math, .tex');
444
mathElements.forEach(el => elementsToProcess.add(el));
445
}
446
});
447
});
448
449
if (elementsToProcess.size > 0) {
450
MathJax.typeset(Array.from(elementsToProcess));
451
}
452
}
453
454
containsMath(element) {
455
const text = element.textContent || '';
456
return text.includes('$') || text.includes('\\(') || text.includes('\\[');
457
}
458
}
459
460
// Start progressive enhancement
461
const enhancer = new MathEnhancer();
462
enhancer.start();
463
```
464
465
## Document States and Lifecycle
466
467
### Processing States
468
469
MathJax processes mathematics through several states:
470
471
```javascript { .api }
472
const STATE = {
473
UNPROCESSED: 0, // Initial state
474
FINDMATH: 10, // Finding math in document
475
COMPILED: 20, // Math compiled to internal format
476
CONVERT: 100, // Converting to output format
477
METRICS: 110, // Computing metrics
478
RERENDER: 125, // Re-rendering if needed
479
TYPESET: 150, // Typesetting complete
480
INSERTED: 200, // Inserted into document
481
LAST: 10000 // Final state
482
};
483
```
484
485
### Lifecycle Hooks
486
487
```javascript
488
// Hook into processing lifecycle
489
MathJax.config.options = {
490
renderActions: {
491
findScript: [150, (doc) => {
492
// Custom script finding logic
493
console.log('Finding scripts in document');
494
}],
495
496
insertedScript: [200, (doc) => {
497
// After insertion callback
498
console.log('Math inserted into document');
499
}]
500
}
501
};
502
```
503
504
### Document Ready Events
505
506
```javascript
507
// Wait for document ready
508
MathJax.whenReady(() => {
509
console.log('MathJax is ready');
510
511
// Safe to perform operations
512
MathJax.typeset();
513
});
514
515
// Promise-based ready handling
516
const mathReady = MathJax.done();
517
mathReady.then(() => {
518
console.log('All math processing complete');
519
});
520
521
// Chained operations
522
MathJax.typesetPromise()
523
.then(() => MathJax.done())
524
.then(() => {
525
console.log('Document fully processed');
526
});
527
```