Integrating MathJax (Version 4) Into a Next.js Application


If you’ve ever tried to write mathematics in a web app, you know the pain of clumsy plaintext: sqrt(x^2 + y^2), 1/2mv^2, or E=mc^2 crammed together without proper symbols. It’s readable in a pinch, but it looks amateurish and quickly becomes impossible for complex equations. With MathJax v4, you can render professional, publication-quality math directly in the browser—complete with fractions, matrices, vectors, and equation numbering—using the same LaTeX syntax mathematicians and scientists rely on every day. This tutorial walks you through setting up MathJax in Next.js and building simple React components so your math looks like math, not like ASCII art.

What You’ll Learn

  • How to set up MathJax v4 with Next.js
  • How to create custom React components for math rendering
  • How to handle MathJax’s asynchronous loading
  • How to write LaTeX expressions in JSX
  • How to configure various LaTeX features including equations, matrices, vectors, and more

Prerequisites

  • Node.js 18+ installed
  • Basic knowledge of React and TypeScript
  • Familiarity with LaTeX syntax

Step 1: Create a New Next.js Project

Create a new Next.js project:

npx create-next-app@latest mathjax-nextjs

You’ll be asked several configuration questions. Here are the recommended answers:

  • Would you like to use TypeScript?
    • Yes
    • Helps catch errors when working with MathJax’s API
  • Would you like to use ESLint?
    • Yes
    • Helps catch errors and enforce consistent style
  • Would you like to use Tailwind?
    • Yes
    • Provides utility classes for styling, though we won’t focus on Tailwind in this tutorial
  • Would you like to use src/ directory?
    • Yes
    • Better project organization
  • Would you like to use the App router?
    • Yes
    • Modern Next.js architecture
  • Would you like to customize the default import alias (@/*)?
    • No
    • We’ll use the default import alias throughout this tutorial

After the project is created, navigate to the project directory:

cd mathjax-nextjs

Here is what your project’s directory should like like:

mathjax-nextjs/
|--src/
|----app/
|------globals.css
|------layout.tsx
|------page.tsx
|--public/
|--package.json
|--tsconfig.json
|--next.config.ts
|--README.md 

Step 2: Install Dependencies

Install the project dependencies:

npm install
npm run dev

Visit http://localhost:3000 to confirm the app is running.

You’re project directory structure should look the same as before:

mathjax-nextjs/
|--src/
|----app/
|------globals.css
|------layout.tsx
|------page.tsx
|--public/
|--package.json
|--tsconfig.json
|--next.config.ts
|--README.md 

Step 3: Configure Next.js for MathJax Support

What we’ll accomplish: Configure Next.js to properly handle MathJas’x font files so mathematical symbols render correctly.

Why this step is needed: MathJax uses special web fonts to display mathematical symbols. Without this configuration, the fonts might not load properly, causing math symbols to appear as boxes or missing characters.

Add a webpack configuration option to handle MathJax font files in the Next.js configuration file at mathjax-nextjs/next.config.ts:

import type {NextConfig} from 'next';

const nextConfig: NextConfig = {
    webpack: (config) => {
        // Handle MathJax static assets
        config.module.rules.push({
            test: /\.woff2$/,
            type: 'asset/resource'
        });
        return config;
    },
};

export default nextConfig;

What is Webpack? Webpack is a module bundler that Next.js uses to combine and optimize your code, styles, and assets. It handles different file types and prepares them for the browser.

Why is this needed for MathJax? MathJax uses web fonts (.woff2 files) to display mathematical symbols. This webpack configuration ensures these font files are properly handled and loaded by the browser, preventing missing or broken math symbols in your rendered equations.

Your project should have the same structure as before:

mathjax-nextjs/
|--src/
|----app/
|------globals.css
|------layout.tsx
|------page.tsx
|--public/
|--package.json
|--tsconfig.json
|--next.config.ts (updated with the webpack configuration)
|--README.md 

Step 4: Load MathJax Using the Page Layout Template

What we’ll accomplish: Load MathJax from CDN and configure it to recognize LaTeX delimiters ($...$ for inline math, $$...$$ for display math) and support various LaTeX features.

Why this step is needed: MathJax needs to be loaded globally so it can scan the entire page for mathematical expressions. The configuration tells MathJax which delimiters to look for and how to process them.

Update src/app/layout.tsx to include the needed MathJax configuration:

import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import './globals.css'

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
  title: 'MathJax v4 + Next.js',
  description: 'MathJax v4 integration with Next.js',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <head>
        {/* MathJax v4 Configuration */}
        <script
          dangerouslySetInnerHTML={{
            __html: `
              MathJax = {
                // LaTeX processing configuration
                tex: {
                  inlineMath: [['$', '$']],
                  displayMath: [['$$', '$$']],
                  processEscapes: true,
                  tags: 'ams',
                  tagSide: 'right',
                  tagIndent: '0.2em'
                },
                // Output rendering configuration
                output: {
                  font: 'mathjax-newcm'
                },
                // Initialization and startup configuration
                startup: {
                  pageReady() {
                    return MathJax.startup.defaultPageReady();
                  }
                }
              };
            `,
          }}
        />
        {/* MathJax v4 CDN */}
        <script defer src="https://cdn.jsdelivr.net/npm/mathjax@4/tex-chtml.js"></script>
      </head>
      <body className={inter.className}>{children}</body>
    </html>
  )
}

Key Configuration Options:

  • inlineMath: [['$', '$']] – Defines delimiters for inline math expressions
  • displayMath: [['$$', '$$']] – Defines delimiters for display math expressions
  • processEscapes: true – Processes LaTeX escape sequences like \\ to \ (needed for backslashes in LaTeX commands)
  • tags: 'ams' – Enables automatic equation numbering
  • tagSide: 'right' – Places equation numbers on the right side
  • tagIndent: '0.2em' – Controls spacing between equations and their numbers

Why dangerouslySetInnerHTML is needed: MathJax needs to process raw HTML strings that contain LaTeX delimiters. The dangerouslySetInnerHTML prop allows us to inject the MathJax configuration script directly into the HTML head, bypassing React’s JSX parsing. This is necessary because MathJax must be configured before the page loads, and the configuration contains JavaScript that needs to be executed as-is.

Why defer is used in the MathJax CDN script: The defer attribute ensures that the MathJax script downloads in parallel with HTML parsing but executes only after the HTML document has been fully parsed. This prevents the script from blocking page rendering while ensuring MathJax is available when the page content loads.

Your project directory should still look the same:

mathjax-nextjs/
|--src/
|----app/
|------globals.css
|------layout.tsx (updated with the needed MathJax configuration)
|------page.tsx
|--public/
|--package.json
|--tsconfig.json
|--next.config.ts (updated with the webpack configuration)
|--README.md 

Step 5: Create TypeScript Declarations

What we’ll accomplish: Define TypeScript type declarations for the global MathJax object so TypeScript understands MathJax’s API and can catch errors.

Why this step is needed: TypeScript needs to know about the MathJax object that gets added to the global window. Without these type declarations, TypeScript will show errors when we try to use window.MathJax.

Create a new file types/mathjax.d.ts in the project root folder (next to package.json) for TypeScript support. This file contains type declarations, not configuration values:

declare global {
  interface Window {
    MathJax: {
      tex: {
        inlineMath: string[][]                      // Delimiters for inline math (e.g., [['$', '$']])
        displayMath: string[][]                   // Delimiters for display math (e.g., [['$$', '$$']])
        processEscapes: boolean             // Whether to process LaTeX escape sequences
        processEnvironments?: boolean // Whether to process LaTeX environments
        tags?: string                                   // Equation numbering style ('ams' for automatic numbering)
        tagSide?: string                             // Side for equation labels ('left' or 'right')
        tagIndent?: string                         // Indentation for equation labels
      }
      output: {
        font: string                  // Math font to use (e.g., 'mathjax-newcm')
        scale?: number          // Overall scaling factor for math
        minScale?: number   // Minimum scale factor
        maxScale?: number  // Maximum scale factor
      }
      startup: {
        pageReady: () => Promise<void>             // Function called when page is ready
        defaultPageReady: () => Promise<void> // Default page ready function
      }
      typesetPromise: (elements?: (Element | null)[]) => Promise<void>  // Function to render math elements
      loader?: {
        paths: { font: string }   // Paths for font loading
        load: string[]                // Extensions to load
      }
    }
  }
}

export {}

Here is what you’re project directory should look like after adding this new file:

mathjax-nextjs/
|--src/
|----app/
|------globals.css
|------layout.tsx (updated with the needed MathJax configuration)
|------page.tsx
|--types/
|----mathjax.d.ts (new file)
|--public/
|--package.json
|--tsconfig.json
|--next.config.ts (updated with the webpack configuration)
|--README.md 

Step 6: Test Basic MathJax Rendering

What we’ll accomplish: Create a simple test page to verify that MathJax is working correctly before building custom components.

Why this step is needed: We need to confirm that MathJax is properly loaded and can render mathematical expressions. This helps us identify any configuration issues early.

Update src/app/page.tsx to test basic MathJax functionality:

import React from 'react'

export default function Home() {
  return (
    <main>
      <h1>MathJax v4 + Next.js Test</h1>
      
      <div>
        <h2>Inline Math Test</h2>
        <p>
          Einstein's equation: $E = mc^2$
        </p>
        <p>
          Pythagorean theorem: $a^2 + b^2 = c^2$
        </p>
        <p>
          Quadratic formula: {`$x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}$`}
        </p>
      </div>
      
      <div>
        <h2>Display Math Test</h2>
        <div>
          $$E = mc^2$$
        </div>
        <div>
          {`$$\\sum_{i=1}^{n} i = \\frac{n(n+1)}{2}$$`}
        </div>
        <div>
          {`$$\\int_{-\\infty}^{\\infty} e^{-x^2} dx = \\sqrt{\\pi}$$`}
        </div>
      </div>

      <div>
        <h2>Aligned Equations</h2>
        <div>
          {`$$\\begin{align} (a + b)^2 &= a^2 + 2ab + b^2 \\\\ &= a^2 + b^2 + 2ab \\\\ &= (a + b)(a + b) \\end{align}$$`}
        </div>
        <div>
          {`$$\\begin{align*} x &= 2y + 3 \\\\ &= 2(y + 1.5) \\\\ &= 2z \\quad \\text{where } z = y + 1.5 \\end{align*}$$`}
        </div>
      </div>

      <div>
        <h2>Matrices and Arrays</h2>
        <div>
          {`$$\\begin{pmatrix} a & b \\\\ c & d \\end{pmatrix}$$`}
        </div>
        <div>
          {`$$\\begin{bmatrix} 1 & 2 & 3 \\\\ 4 & 5 & 6 \\\\ 7 & 8 & 9 \\end{bmatrix}$$`}
        </div>
        <div>
          {`$$\\begin{vmatrix} a & b \\\\ c & d \\end{vmatrix} = ad - bc$$`}
        </div>
        <div>
          {`$$\\begin{array}{|c|c|c|} \\hline x & y & x + y \\\\ \\hline 1 & 2 & 3 \\\\ 4 & 5 & 9 \\\\ 7 & 8 & 15 \\\\ \\hline \\end{array}$$`}
        </div>
      </div>

      <div>
        <h2>Vectors</h2>
        <div>
          {`$$\\vec{v} = \\begin{pmatrix} x \\\\ y \\\\ z \\end{pmatrix}$$`}
        </div>
        <div>
          {`$$\\mathbf{v} = v_x\\hat{i} + v_y\\hat{j} + v_z\\hat{k}$$`}
        </div>
        <div>
          {`$$\\|\\vec{v}\\| = \\sqrt{v_x^2 + v_y^2 + v_z^2}$$`}
        </div>
      </div>

      <div>
        <h2>Equation Labels and References</h2>
        <div>
          {`$$\\begin{equation} E = mc^2 \\label{eq:einstein} \\end{equation}$$`}
        </div>
        <div>
          {`$$\\begin{equation} F = ma \\label{eq:newton} \\end{equation}$$`}
        </div>
        <div>
          {`$$\\begin{equation} \\sum_{i=1}^{n} i = \\frac{n(n+1)}{2} \\label{eq:sum} \\end{equation}$$`}
        </div>
        <p>Referencing equations: Einstein's equation ({`\\ref{eq:einstein}`}) and Newton's law ({`\\ref{eq:newton}`}).</p>
      </div>

      <div>
        <h2>Advanced Examples</h2>
        <div>
          {`$$\\begin{align} \\nabla \\cdot \\mathbf{E} &= \\frac{\\rho}{\\epsilon_0} \\label{eq:gauss} \\\\ \\nabla \\cdot \\mathbf{B} &= 0 \\label{eq:gauss-mag} \\\\ \\nabla \\times \\mathbf{E} &= -\\frac{\\partial \\mathbf{B}}{\\partial t} \\label{eq:faraday} \\\\ \\nabla \\times \\mathbf{B} &= \\mu_0\\mathbf{J} + \\mu_0\\epsilon_0\\frac{\\partial \\mathbf{E}}{\\partial t} \\label{eq:ampere} \\end{align}$$`}
        </div>
        <p>Maxwell's equations: {`\\ref{eq:gauss}`}, {`\\ref{eq:gauss-mag}`}, {`\\ref{eq:faraday}`}, and {`\\ref{eq:ampere}`}.</p>
      </div>
    </main>
  )
}

Now test the setup:

  1. Save the file and check your browser at http://localhost:3000
  2. You should see the mathematical expressions rendered properly
  3. If you see raw LaTeX (like $E = mc^2$), MathJax isn’t working
  4. If you see properly rendered math symbols, MathJax is working correctly

Note: a hard browser refresh may be needed to see the changes.

Important: LaTeX Syntax in JSX

When writing LaTeX expressions in JSX, you’ll notice two different syntax approaches in the examples above:

Simple Expressions (Direct TSX)

<p>Einstein's equation: $E = mc^2$</p>
<div>$$E = mc^2$$</div>

Complex Expressions (Template Literals)

<div>{`$$\\sum_{i=1}^{n} i = \\frac{n(n+1)}{2}$$`}</div>

Why the difference:

  • Simple expressions like E = mc^2 can be written directly in JSX without special handling
  • Complex expressions with backslashes (\frac, \sum, \sqrt, \begin, etc.) need template literals ({``}) because JSX treats backslashes as escape characters
  • Template literals allow you to write raw LaTeX without JSX parsing issues

Template literals allow for multi-line formatting, a common practice when writing LaTeX code for readability:

<DisplayMath>{`
  \\begin{pmatrix} 
    a & b \\\\ 
    c & d 
  \\end{pmatrix}
`}</DisplayMath>

This makes complex LaTeX expressions much more readable and organized, especially for matrices, arrays, and multi-line equations.

Rule of thumb: If your LaTeX contains backslashes, wrap it in template literals:

{`your LaTeX here`}

Your project directory should now look like this:

mathjax-nextjs/
|--src/
|----app/
|------globals.css
|------layout.tsx (updated with the needed MathJax configuration)
|------page.tsx (updated with examples to test rendering)
|--types/
|----mathjax.d.ts (new file)
|--public/
|--package.json
|--tsconfig.json
|--next.config.ts (updated with the webpack configuration)
|--README.md 

Basic MathJax Integration Complete!

At this point, you have a working MathJax v4 integration with Next.js! The setup above will render any LaTeX expressions you write directly in your JSX using $...$ for inline math and $$...$$ for display math. This approach works perfectly for simple use cases and is great for testing.


Creating Custom Math Components

While the basic integration works well, creating custom React components for math rendering provides significant benefits:

  • Better Developer Experience: Clean, semantic component names like <InlineMath> and <DisplayMath> make your code more readable
  • Reusable Logic: Centralized error handling, loading checks, and MathJax integration
  • Type Safety: Full TypeScript support with proper prop types and error checking
  • Consistent Styling: Standardized appearance and spacing across your application
  • Advanced Features: Easy to add features like equation labeling, custom styling, performance optimizations, and specialized math environments
  • Maintainability: Changes to MathJax configuration or rendering logic only need to be made in one place

Let’s create these components to enhance your math rendering capabilities.

Step 7: Create the Components Directory

What we’ll accomplish: Create a directory to organize our custom MathJax components.

Why this step is needed: We’ll be creating multiple React components for math rendering, so we need a dedicated directory to keep them organized and separate from pages.

Create a directory to organize our custom MathJax components:

mkdir src/app/components

Now you’re project should look like this:

mathjax-nextjs/
|--src/
|----app/
|------components/ (new directory to store our custom components)
|------globals.css
|------layout.tsx (updated with the needed MathJax configuration)
|------page.tsx (updated with examples to test rendering)
|--types/
|----mathjax.d.ts (new file)
|--public/
|--package.json
|--tsconfig.json
|--next.config.ts (updated with the webpack configuration)
|--README.md 

Step 8: Create the InlineMath Component

What we’ll accomplish: Create a React component that renders inline mathematical expressions (math that appears within text).

Why this step is needed: We need a reusable component that can take LaTeX as input and render it as inline math. The component uses dangerouslySetInnerHTML to inject the LaTeX with $...$ delimiters so MathJax can process it.

Create src/app/components/InlineMath.tsx:

'use client'

// React hooks for managing component lifecycle and DOM references
import { useEffect, useRef } from 'react'

// TypeScript interface defining the component's props
interface InlineMathProps {
  children: string
  className?: string
}

const InlineMath = ({ children, className = '' }: InlineMathProps) => {

  // Reference to the DOM element that will contain the math
  const mathRef = useRef<HTMLSpanElement>(null)

  // Effect hook to handle MathJax typesetting when component mounts or children change
  useEffect(() => {
    const typesetMath = () => {
      // Check if MathJax is loaded and ready to typeset
      if (mathRef.current && (window as any).MathJax && (window as any).MathJax.typesetPromise) {
        (window as any).MathJax.typesetPromise([mathRef.current])
          .catch((err: any) => {
            if (typeof console !== 'undefined' && console.error) {
              console.error('InlineMath typesetting error:', err)
            }
          })
      // If MathJax is loaded but typesetPromise isn't ready yet, retry after a short delay
      } else if (mathRef.current && (window as any).MathJax) {
        setTimeout(typesetMath, 50)
      }
    }

    // Check if we're in a browser environment and MathJax is already loaded
    if (typeof window !== 'undefined' && (window as any).MathJax) {
      typesetMath()
    } else {
      // If MathJax isn't loaded yet, poll for it with exponential backoff
      const checkMathJax = () => {
        if ((window as any).MathJax && (window as any).MathJax.typesetPromise) {
          typesetMath()
        } else {
          setTimeout(checkMathJax, 100)
        }
      }
      // Start polling for MathJax to load
      setTimeout(checkMathJax, 100)
    }
  }, [children])

  return (
    // Span element that will contain the LaTeX and be processed by MathJax
    <span 
      ref={mathRef} 
      className={`inline-math ${className}`}
      dangerouslySetInnerHTML={{ __html: `$${children}$` }}
    />
  )
}

export default InlineMath

Your project directory should now look like this:

mathjax-nextjs/
|--src/
|----app/
|------components/ (new directory to store our custom components)
|--------InlineMath.tsx (new file)
|------globals.css
|------layout.tsx (updated with the needed MathJax configuration)
|------page.tsx (updated with examples to test rendering)
|--types/
|----mathjax.d.ts (new file)
|--public/
|--package.json
|--tsconfig.json
|--next.config.ts (updated with the webpack configuration)
|--README.md 

Step 9: Create the DisplayMath Component

What we’ll accomplish: Create a React component that renders display mathematical expressions (math that appears on its own line, centered) with optimized width for better equation label positioning.

Why this step is needed: Display math needs different formatting than inline math. This component renders LaTeX with $$...$$ delimiters and uses 50% width to naturally bring equation labels closer to the equations.

Create src/app/components/DisplayMath.tsx:

'use client'

// React hooks for managing component lifecycle and DOM references
import { useEffect, useRef } from 'react'

// TypeScript interface defining the component's props
interface DisplayMathProps {
  children: string
  className?: string
  centered?: boolean
}

const DisplayMath = ({ children, className = '', centered = true }: DisplayMathProps) => {
  // Reference to the DOM element that will contain the math
  const mathRef = useRef<HTMLDivElement>(null)

  // Effect hook to handle MathJax typesetting when component mounts or children change
  useEffect(() => {
    const typesetMath = () => {
      // Check if MathJax is loaded and ready to typeset
      if (mathRef.current && (window as any).MathJax && (window as any).MathJax.typesetPromise) {
        (window as any).MathJax.typesetPromise([mathRef.current])
          .catch((err: any) => {
            if (typeof console !== 'undefined' && console.error) {
              console.error('DisplayMath typesetting error:', err)
            }
          })
      // If MathJax is loaded but typesetPromise isn't ready yet, retry after a short delay
      } else if (mathRef.current && (window as any).MathJax) {
        setTimeout(typesetMath, 50)
      }
    }

    // Check if we're in a browser environment and MathJax is already loaded
    if (typeof window !== 'undefined' && (window as any).MathJax) {
      typesetMath()
    } else {
      // If MathJax isn't loaded yet, poll for it with exponential backoff
      const checkMathJax = () => {
        if ((window as any).MathJax && (window as any).MathJax.typesetPromise) {
          typesetMath()
        } else {
          setTimeout(checkMathJax, 100)
        }
      }
      // Start polling for MathJax to load
      setTimeout(checkMathJax, 100)
    }
  }, [children])

  return (
    // Div element that will contain the LaTeX and be processed by MathJax
    <div 
      ref={mathRef} 
      className={`display-math ${centered ? 'text-center' : ''} ${className}`}
      style={{ margin: '1rem 0', width: '50%', marginLeft: 'auto', marginRight: 'auto' }}
      dangerouslySetInnerHTML={{ __html: `$$${children}$$` }}
    />
  )
}

export default DisplayMath

With this last file, your final project directory should now look like this:

mathjax-nextjs/
|--src/
|----app/
|------components/ (new directory to store our custom components)
|--------InlineMath.tsx (new file)
|--------DisplayMath.tsx (new file)
|------globals.css
|------layout.tsx (updated with the needed MathJax configuration)
|------page.tsx (updated with examples to test rendering)
|--types/
|----mathjax.d.ts (new file)
|--public/
|--package.json
|--tsconfig.json
|--next.config.ts (updated with the webpack configuration)
|--README.md 

Step 10: Update the Examples On the Main Page to Use the InlineMath and DisplayMath Components

What we’ll accomplish: Create a comprehensive demonstration page that shows how to use our custom MathJax components with various types of mathematical expressions.

Why this step is needed: We need to test our components and provide examples of how to use them. This page will showcase both simple and complex mathematical expressions, demonstrating the full capabilities of our MathJax integration.

Update src/app/page.tsx to demonstrate the components:

import React from 'react'
import InlineMath from './components/InlineMath'
import DisplayMath from './components/DisplayMath'

export default function Home() {
  return (
    <main>
      <h1>MathJax v4 + Next.js Test</h1>

      <div>
        <h2>Inline Math Test</h2>
        <p>
          Einstein's equation: <InlineMath>E = mc^2</InlineMath>
        </p>
        <p>
          Pythagorean theorem: <InlineMath>a^2 + b^2 = c^2</InlineMath>
        </p>
      </div>

      <div>
        <h2>Display Math Test</h2>
        <div>
          <DisplayMath>E = mc^2</DisplayMath>
        </div>
        <div>
          <DisplayMath>{`
            \\sum_{i=1}^{n} i = \\frac{n(n+1)}{2}
          `}</DisplayMath>
        </div>
      </div>

      <div>
        <h2>Colored Math Examples</h2>
        
        <h3>Inline Colored Math</h3>
        <p>
          <InlineMath>{`E = \\color{red}{mc^2}`}</InlineMath>
        </p>
        <p>
          <InlineMath>{`\\color{blue}{x^2} + \\color{green}{y^2} = \\color{red}{z^2}`}</InlineMath>
        </p>
        <p>
          <InlineMath>{`f(x) = \\color{red}{x^2} + \\color{blue}{2x} + \\color{green}{1}`}</InlineMath>
        </p>

        <h3>Display Colored Math</h3>
        <DisplayMath>
          {`\\color{red}{E} = \\color{blue}{mc^2} + \\color{green}{\\frac{1}{2}mv^2}`}
        </DisplayMath>
        
        <DisplayMath>
          {`\\frac{\\color{red}{numerator}}{\\color{blue}{denominator}} = \\color{green}{result}`}
        </DisplayMath>
        
        <DisplayMath>
          {`\\color{red}{x}^{\\color{blue}{2}} + \\color{green}{y}_{\\color{magenta}{i}} = \\color{cyan}{z}`}
        </DisplayMath>

        <h3>RGB and Hex Colors</h3>
        <DisplayMath>
          {`\\color[rgb]{0.5,0.8,0.2}{RGB Color} + \\color{#FF5733}{Hex Color}`}
        </DisplayMath>
      </div>

      <div>
        <h2>Advanced Math Examples</h2>
        
        <h3>Matrices and Arrays</h3>
        <DisplayMath>
          {`
            \\begin{pmatrix} 
              a & b \\\\ 
              c & d 
            \\end{pmatrix}
          `}
        </DisplayMath>
        
        <DisplayMath>
          {`
            \\begin{bmatrix} 
              1 & 2 & 3 \\\\ 
              4 & 5 & 6 \\\\ 
              7 & 8 & 9 
            \\end{bmatrix}
          `}
        </DisplayMath>
        
        <DisplayMath>
          {`
            \\begin{vmatrix} 
              a & b \\\\ 
              c & d 
            \\end{vmatrix} = ad - bc
          `}
        </DisplayMath>

        <h3>Vectors</h3>
        <DisplayMath>
          {`
            \\vec{v} = \\begin{pmatrix} 
              x \\\\ 
              y \\\\ 
              z 
            \\end{pmatrix}
          `}
        </DisplayMath>
        
        <DisplayMath>
          {`
            \\mathbf{v} = v_x\\hat{i} + v_y\\hat{j} + v_z\\hat{k}
          `}
        </DisplayMath>

        <h3>Aligned Equations</h3>
        <DisplayMath>
          {`
            \\begin{align} 
              (a + b)^2 &= a^2 + 2ab + b^2 \\\\ 
              &= a^2 + b^2 + 2ab \\\\ 
              &= (a + b)(a + b) 
            \\end{align}
          `}
        </DisplayMath>
        
        <DisplayMath>
          {`
            \\begin{align*} 
              x &= 2y + 3 \\\\ 
              &= 2(y + 1.5) \\\\ 
              &= 2z \\quad \\text{where } z = y + 1.5 
            \\end{align*}
          `}
        </DisplayMath>

        <h3>Labeled Equations</h3>
        <DisplayMath>
          {`\\begin{equation} E = mc^2 \\label{eq:einstein} \\end{equation}`}
        </DisplayMath>
        
        <DisplayMath>
          {`\\begin{equation} F = ma \\label{eq:newton} \\end{equation}`}
        </DisplayMath>
        
        <DisplayMath>
          {`\\begin{equation} \\sum_{i=1}^{n} i = \\frac{n(n+1)}{2} \\label{eq:sum} \\end{equation}`}
        </DisplayMath>
        
        <p>Referencing equations: Einstein's equation ({`\\ref{eq:einstein}`}) and Newton's law ({`\\ref{eq:newton}`}).</p>

        <h3>Cases and Piecewise Functions</h3>
        <DisplayMath>
          {`
            f(x) = \\begin{cases} 
              x^2 & \\text{if } x > 0 \\\\ 
              0 & \\text{if } x = 0 \\\\ 
              -x^2 & \\text{if } x < 0 
            \\end{cases}
          `}
        </DisplayMath>

        <h3>Tables</h3>
        <DisplayMath>
          {`
            \\begin{array}{|c|c|c|} 
              \\hline 
              x & y & x + y \\\\ 
              \\hline 
              1 & 2 & 3 \\\\ 
              4 & 5 & 9 \\\\ 
              7 & 8 & 15 \\\\ 
              \\hline 
            \\end{array}
          `}
        </DisplayMath>

        <h3>Complex Examples</h3>
        <DisplayMath>
          {`
            \\begin{align} 
              \\nabla \\cdot \\mathbf{E} &= \\frac{\\rho}{\\epsilon_0} \\label{eq:gauss} \\\\ 
              \\nabla \\cdot \\mathbf{B} &= 0 \\label{eq:gauss-mag} \\\\ 
              \\nabla \\times \\mathbf{E} &= -\\frac{\\partial \\mathbf{B}}{\\partial t} \\label{eq:faraday} \\\\ 
              \\nabla \\times \\mathbf{B} &= \\mu_0\\mathbf{J} + \\mu_0\\epsilon_0\\frac{\\partial \\mathbf{E}}{\\partial t} \\label{eq:ampere} 
            \\end{align}
          `}
        </DisplayMath>
        
        <p>Maxwell's equations: {`\\ref{eq:gauss}`}, {`\\ref{eq:gauss-mag}`}, {`\\ref{eq:faraday}`}, and {`\\ref{eq:ampere}`}.</p>
      </div>
    </main>
  )
}

How the Components Work

Why dangerouslySetInnerHTML is Required in Components

MathJax needs to process raw HTML strings that contain LaTeX delimiters like $...$ or $$...$$. When you write:

// This doesn't work - JSX treats it as text
<InlineMath>E = mc^2</InlineMath>

JSX treats E = mc^2 as plain text, not as LaTeX that needs MathJax processing.

The solution is to inject the LaTeX content as HTML so MathJax can process it:

// This works - MathJax can process the HTML
<span dangerouslySetInnerHTML={{ __html: `$E = mc^2$` }} />

The Process

// 1. User writes: <InlineMath>E = mc^2</InlineMath>

// 2. Component converts to: <span dangerouslySetInnerHTML={{ __html: `$E = mc^2$` }} />

// 3. Browser renders: <span>$E = mc^2$</span>

// 4. MathJax scans DOM, finds $E = mc^2$, and replaces it with rendered math

Why 50% Width for DisplayMath?

The <DisplayMath> component uses specific styling to optimize equation layout:

  • 50% width (width: '50%'): Makes equations narrower, naturally bringing equation labels closer
  • Auto margins (marginLeft: 'auto', marginRight: 'auto'): Centers the equations horizontally
  • Vertical spacing (margin: '1rem 0'): Adds consistent spacing above and below equations

Customization: All these values can be modified in the component’s style prop to match your design preferences. For example, you could change the width to 75% for wider equations, adjust the margins for different spacing, or remove the styling entirely for full-width display.


Usage Examples

Basic Component Usage

// Import components
import InlineMath from './components/InlineMath'
import DisplayMath from './components/DisplayMath'

// Simple expressions (no special characters)
<InlineMath>E = mc^2</InlineMath>
<DisplayMath>E = mc^2</DisplayMath>

// Complex expressions (using template literals for backslashes)
<InlineMath>{`x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}`}</InlineMath>
<DisplayMath>{`
  \\sum_{i=1}^{n} i = \\frac{n(n+1)}{2}
`}</DisplayMath>

Equation Labeling and Cross-References

// Labeled equations
<DisplayMath>
  {`\\begin{equation} E = mc^2 \\label{eq:einstein} \\end{equation}`}
</DisplayMath>

<DisplayMath>
  {`\\begin{equation} F = ma \\label{eq:newton} \\end{equation}`}
</DisplayMath>

// Cross-references
<p>Einstein's equation ({`\\ref{eq:einstein}`}) and Newton's law ({`\\ref{eq:newton}`}).</p>

Colored Math

// Named colors
<InlineMath>{`\\color{red}{text}`}</InlineMath>

// RGB colors
<DisplayMath>{`\\color[rgb]{0.5,0.8,0.2}{text}`}</DisplayMath>

// Hex colors
<InlineMath>{`\\color{#FF5733}{text}`}</InlineMath>

Matrices and Arrays

// 2x2 matrix with parentheses
<DisplayMath>{`
  \\begin{pmatrix} 
    a & b \\\\ 
    c & d 
  \\end{pmatrix}
`}</DisplayMath>

// 3x3 matrix with brackets
<DisplayMath>{`
  \\begin{bmatrix} 
    1 & 2 & 3 \\\\ 
    4 & 5 & 6 \\\\ 
    7 & 8 & 9 
  \\end{bmatrix}
`}</DisplayMath>

// Determinant
<DisplayMath>{`
  \\begin{vmatrix} 
    a & b \\\\ 
    c & d 
  \\end{vmatrix} = ad - bc
`}</DisplayMath>

// Table with borders
<DisplayMath>{`
  \\begin{array}{|c|c|c|} 
    \\hline 
    x & y & x + y \\\\ 
    \\hline 
    1 & 2 & 3 \\\\ 
    4 & 5 & 9 \\\\ 
    \\hline 
  \\end{array}
`}</DisplayMath>

Vectors

// Vector with arrow
<DisplayMath>{`
  \\vec{v} = \\begin{pmatrix} 
    x \\\\ 
    y \\\\ 
    z 
  \\end{pmatrix}
`}</DisplayMath>

// Bold vector with unit vectors
<DisplayMath>{`
  \\mathbf{v} = v_x\\hat{i} + v_y\\hat{j} + v_z\\hat{k}
`}</DisplayMath>

// Vector magnitude
<DisplayMath>{`
  \\|\\vec{v}\\| = \\sqrt{v_x^2 + v_y^2 + v_z^2}
`}</DisplayMath>

Aligned Equations

// Aligned equations with numbering
<DisplayMath>{`
  \\begin{align} 
    (a + b)^2 &= a^2 + 2ab + b^2 \\\\ 
    &= a^2 + b^2 + 2ab \\\\ 
    &= (a + b)(a + b) 
  \\end{align}
`}</DisplayMath>

// Aligned equations without numbering
<DisplayMath>{`
  \\begin{align*} 
    x &= 2y + 3 \\\\ 
    &= 2(y + 1.5) \\\\ 
    &= 2z \\quad \\text{where } z = y + 1.5 
  \\end{align*}
`}</DisplayMath>

Piecewise Functions

// Piecewise defined function
<DisplayMath>{`
  f(x) = \\begin{cases} 
    x^2 & \\text{if } x > 0 \\\\ 
    0 & \\text{if } x = 0 \\\\ 
    -x^2 & \\text{if } x < 0 
  \\end{cases}
`}</DisplayMath>

// Multiple conditions
<DisplayMath>{`
  g(x) = \\begin{cases} 
    2x + 1 & \\text{if } x < 0 \\\\ 
    x^2 & \\text{if } 0 \\leq x < 1 \\\\ 
    \\sqrt{x} & \\text{if } x \\geq 1 
  \\end{cases}
`}</DisplayMath>

Troubleshooting

Common Issues

IssueSolution
Math not renderingCheck browser console for errors, ensure MathJax CDN is loading
TypeScript errorsVerify types/mathjax.d.ts file exists and is properly configured
Component not foundVerify import paths and component file names
Math not renderingCheck browser console for errors, ensure MathJax CDN is loading
Math not renderingCheck browser console for errors, ensure MathJax CDN is loading

Debug Steps

  1. Check Console: Open browser developer tools and look for errors
  2. Verify MathJax Loading: Check if window.MathJax exists in console
  3. Test Simple Math: Try basic expressions first before complex ones
  4. Check Network: Ensure MathJax CDN is accessible
  5. Verify Configuration: Ensure MathJax config includes proper delimiters and font settings

Final Project Structure

mathjax-nextjs/
|--src/
|----app/
|------components/ (new directory to store our custom components)
|--------InlineMath.tsx (new file)
|--------DisplayMath.tsx (new file)
|------globals.css
|------layout.tsx (updated with the needed MathJax configuration)
|------page.tsx (updated with examples to test rendering)
|--types/
|----mathjax.d.ts (new file)
|--public/
|--package.json
|--tsconfig.json
|--next.config.ts (updated with the webpack configuration)
|--README.md 

References

Documentation

Useful Links


Conclusion

This tutorial provides a complete solution for integrating MathJax v4 with Next.js. The custom components offer a clean, developer-friendly way to display mathematical expressions while maintaining full TypeScript support.

Key features include:

  • Custom React components for inline and display math
  • Advanced LaTeX features including matrices, vectors, and aligned equations
  • Color support for highlighting different parts of equations

The solution is production-ready and can be extended with additional features like custom fonts, advanced styling, and performance optimizations based on your specific requirements.


All of the code, and the tutorial, were written using generative AI. The tutorial was slightly modified by hand.