Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/shuding/nextra/llms.txt

Use this file to discover all available pages before exploring further.

The mdx-components file is the central place to customize how standard Markdown elements — headings, links, images, code blocks, and more — are rendered throughout your Nextra site. By exporting a single useMDXComponents function from this file, you can override any HTML element with your own React component globally, without touching individual MDX pages.

Why This File Exists

When @mdx-js/mdx compiles an MDX file, it resolves component overrides through an import path aliased as next-mdx-import-source-file. Nextra maps that alias to your mdx-components file, so every compiled MDX page automatically picks up your overrides. This is the same mechanism used by Next.js’s official @next/mdx package, extended by Nextra for its own defaults (image zoom, syntax highlighting, anchor links, etc.).

File Location

The mdx-components file can live at the project root or inside src/:
your-project/
├── mdx-components.tsx    ← root-level (detected automatically)
└── src/
    └── mdx-components.tsx ← also detected automatically
The .js, .jsx, and .tsx file extensions are all supported.

Required Export

The file must export a function named useMDXComponents. This function receives the components passed in by the current MDX context and returns the merged component map:
mdx-components.ts
import { useMDXComponents as getThemeComponents } from 'nextra-theme-docs' // or nextra-theme-blog

// Retrieve the default components from your Nextra theme
const themeComponents = getThemeComponents()

// Merge and export
export function useMDXComponents(components) {
  return {
    ...themeComponents,
    ...components
  }
}

Overriding Elements

Spread the theme’s defaults and then add your own overrides. Any standard HTML tag name is a valid key:
mdx-components.tsx
import { useMDXComponents as getNextraMDXComponents } from 'nextra/mdx-components'

export function useMDXComponents(components) {
  return {
    ...getNextraMDXComponents(components),
    // Override the <h1> element with a custom styled heading
    h1: ({ children }) => (
      <h1 className="my-custom-h1 text-4xl font-bold">{children}</h1>
    ),
    // Wrap all <a> tags in a custom link component
    a: ({ href, children }) => (
      <a href={href} className="text-blue-600 underline hover:no-underline">
        {children}
      </a>
    ),
    // Replace <img> with a custom image renderer
    img: ({ src, alt }) => (
      <img src={src} alt={alt} className="rounded-lg shadow-md" />
    ),
  }
}
Always spread the theme’s components (...getNextraMDXComponents(components) or ...themeComponents) first. Placing your overrides after the spread ensures they take precedence without discarding Nextra’s built-in enhancements.

How Next.js Resolves the File

Nextra sets up a module alias next-mdx-import-source-file that points to your mdx-components file. This alias is declared in Nextra’s type definitions:
// nextra/src/env.d.ts
declare module 'next-mdx-import-source-file' {
  export { useMDXComponents } from 'nextra/mdx-components'
}
At runtime, every compiled MDX page imports useMDXComponents from next-mdx-import-source-file, which resolves to your project’s mdx-components file. This wiring happens automatically — no manual alias configuration is needed for webpack builds.

Turbopack: Fixing the next-mdx-import-source-file Error

When using Turbopack, the automatic alias resolution may not be configured. If you see:
Module not found: Can't resolve 'next-mdx-import-source-file'
Add the alias manually in next.config.mjs:
next.config.mjs
import nextra from 'nextra'

const withNextra = nextra()

export default withNextra({
  turbopack: {
    resolveAlias: {
      // Adjust the path and extension to match your actual file
      'next-mdx-import-source-file': './src/mdx-components.tsx'
    }
  }
})

Avoiding False ESLint Positives

The React Hooks ESLint plugin treats any function whose name starts with use as a hook and warns if you call it at the module’s top level. To avoid this false positive when importing useMDXComponents, alias it on import:
mdx-components.tsx
// ✅ Alias to getMDXComponents to avoid the lint warning
import { useMDXComponents as getMDXComponents } from 'nextra-theme-docs'

const themeComponents = getMDXComponents() // not treated as a hook call

export function useMDXComponents(components) {
  return {
    ...themeComponents,
    ...components
  }
}
Without the alias you would see:
React Hook "useMDXComponents" cannot be called at the top level.
React Hooks must be called in a React function component or a custom React Hook function.

Using src/ Directory

If your project uses a src/ layout, move mdx-components into src/:
your-project/
├── src/
│   ├── app/
│   ├── content/
│   └── mdx-components.tsx  ← works here too
├── next.config.mjs
└── package.json
Nextra detects src/mdx-components automatically, the same way it detects src/content. Remember to update the Turbopack resolveAlias path if you’re using Turbopack.

Build docs developers (and LLMs) love