mui-markdown
Render Markdown / MDX with MUI components — powered by markdown-to-jsx.
- Markdown components adapt to your MUI theme automatically
- Optional syntax highlighting via
prism-react-renderer - Optional diagram support via
mermaid - Optional math support via
katex - Table of contents extraction with
extractHeadings - GFM task lists rendered with MUI
Checkbox, plus native footnote support
Contributors
Installation
# with npm npm i mui-markdown@latest # with yarn yarn add mui-markdown
mui-markdown v3 requires markdown-to-jsx v9 or newer as a peer dependency. See the CHANGELOG for migration notes if you're upgrading from v2.Quick Start
The example below renders the h1 tag using the MUI Typography component.
App.jsximport React from 'react';
import { MuiMarkdown } from 'mui-markdown';
const App = () => {
return <MuiMarkdown>{`# Hello markdown!`}</MuiMarkdown>;
};
export default App;A default export is also available (import MuiMarkdown from 'mui-markdown'), but the named import is recommended.
Props
Props available on the MuiMarkdown component. All props are optional.
| Name | Type | Default |
|---|---|---|
key | React.key | - |
children | string | - |
overrides* | MarkdownToJSX.Overrides | defaultOverrides |
options* | MarkdownToJSX.Options | - |
codeWrapperStyles | CSSProperties | - |
prismTheme | PrismTheme | vsDark |
Highlight | HighlightComponent | - |
customTableScrollbar | boolean | false |
hideLineNumbers | boolean | false |
name | string | - |
copiable | boolean | false |
CopyComponent | ComponentType<CopyComponentProps> | - |
copiedLabel | string | 'Copied!' |
copyLabel | string | 'Copy code' |
copyIcon | ReactNode | - |
copiedIcon | ReactNode | - |
copyButtonSx | SxProps<Theme> | - |
showFileIcon | boolean | true |
fileIcon | ReactNode | - |
FileNameComponent | ComponentType | Typography |
fileNameSx | SxProps<Theme> | - |
fileNameWrapperSx | SxProps<Theme> | - |
useHighlightThemeBackground | boolean | false |
highlightColor | string | 'info.main' |
removedColor | string | 'error.main' |
insertedColor | string | 'success.main' |
enableMermaid | boolean | false |
mermaidConfig | MermaidConfig | - |
Diagram* | DiagramComponent | - |
enableMath | boolean | false |
katexOptions | KatexOptions | - |
MathComponent* | MathBlockComponent | - |
overrides and options at the same time.
Using customTableScrollbar converts tables to client-side components.
You must provide the Diagram component if you've enabled mermaid,
and the MathComponent if you've enabled math support.
Overrides
Optionally override any tag to use your own component. Spread defaultOverrides to keep the other default overrides.
Override with a regular HTML tag
App.tsximport React from 'react';
import { MuiMarkdown, defaultOverrides } from 'mui-markdown';
const App = () => {
return (
<MuiMarkdown
overrides={{
...defaultOverrides, // Keeps the other default overrides.
h1: {
component: 'p',
props: {
style: { color: 'red' },
} as React.HTMLProps<HTMLParagraphElement>,
},
}}
>
{`# Hello markdown!`}
</MuiMarkdown>
);
};
export default App;In plain JS/JSX, drop the as React.HTMLProps<...> assertion.
Override with your own component
App.tsximport React from 'react';
import { MuiMarkdown, defaultOverrides } from 'mui-markdown';
import CustomTypography, {
CustomTypographyProps,
} from './components/CustomTypography';
const App = () => {
return (
<MuiMarkdown
overrides={{
...defaultOverrides, // Keeps the other default overrides.
h1: {
component: CustomTypography,
props: {
// custom props
} as CustomTypographyProps,
},
}}
>
{`# Hello markdown!`}
</MuiMarkdown>
);
};
export default App;Options
Parsing options are passed straight through to markdown-to-jsx — see its parsing options documentation.
overrides property inside options. Don't use the overrides and options props together on the MuiMarkdown component.Code Wrapper Styles
Pass your desired styles for the syntax highlighter component via codeWrapperStyles. These are the defaults:
borderRadius: '0.5rem', padding: '0.5rem 0.75rem', overflow: 'auto',
Syntax Highlight
mui-markdown uses prism-react-renderer to highlight code blocks. It's an optional dependency — install it only if you want highlighting:
# with npm npm i prism-react-renderer # with yarn yarn add prism-react-renderer
Then pass Highlight and themes to the component. Change the theme with prismTheme, and hide line numbers with hideLineNumbers:
App.tsximport React from 'react';
import { MuiMarkdown } from 'mui-markdown';
import { Highlight, themes } from 'prism-react-renderer';
const App = () => {
return (
<MuiMarkdown
Highlight={Highlight}
themes={themes}
prismTheme={themes.github}
hideLineNumbers
>
{`# Hello markdown!`}
</MuiMarkdown>
);
};
export default App;When using overrides, get highlighting by passing Highlight, themes, and your theme to getOverrides:
App.tsximport React from 'react';
import { MuiMarkdown, getOverrides } from 'mui-markdown';
import { Highlight, themes } from 'prism-react-renderer';
const App = () => {
return (
<MuiMarkdown
overrides={{
...getOverrides({ Highlight, themes, theme: themes.github }),
h1: {
component: 'p',
props: {
style: { color: 'red' },
},
},
}}
>
{`# Hello markdown!`}
</MuiMarkdown>
);
};
export default App;Enhanced Code Block Features
Advanced code block features for better documentation and code presentation.
| Feature | Markdown Attribute | Global Prop | Description |
|---|---|---|---|
| Line Highlighting | highlighted="1,3-5" | - | Highlights specific lines with blue background |
| Removed Lines | removed="2,4" | - | Shows deletion lines with red background and - prefix |
| Inserted Lines | inserted="3,5-7" | - | Shows addition lines with green background and + prefix |
| File Name | name="path/file.ts" | name="path/file.ts" | Displays file name/path above code block |
| Copy Button | copiable | copiable={true} | Adds a copy-to-clipboard button |
| Hide Line Numbers | hideLineNumbers | hideLineNumbers={true} | Toggles line number visibility |
Highlighting important lines
```tsx highlighted="2,4-6"
function Button({ children }) {
const [clicked, setClicked] = useState(false);
const handleClick = () => {
setClicked(true);
};
return <button onClick={handleClick}>{children}</button>;
}
```Showing code diffs
```tsx removed="2" inserted="3"
export async function getUser(id) {
const url = `/api/user/${id}`;
const url = `/api/v2/users/${id}`;
return fetch(url).then((r) => r.json());
}
```File name with copy button
```tsx name="components/Header.tsx" copiable
export function Header({ title }) {
return (
<header>
<h1>{title}</h1>
</header>
);
}
```Combined features
```tsx name="src/utils/validator.ts" highlighted="4-6" removed="7" inserted="8" copiable hideLineNumbers
export function validateEmail(email: string): boolean {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!email) {
return false;
}
const trimmedEmail = email.trimEnd();
const trimmedEmail = email.trim();
return regex.test(trimmedEmail);
}
```Line range syntax
The line range parser supports flexible syntax:
- Single lines:
"1"or"1,2,3" - Ranges:
"1-5"or"1-5,8-10" - Mixed:
"1,3-5,7,9-12"
Global Configuration
Set defaults for all code blocks using getOverrides:
App.tsximport { MuiMarkdown, getOverrides } from 'mui-markdown';
import { Highlight, themes } from 'prism-react-renderer';
const overrides = getOverrides({
Highlight,
themes,
copiable: true, // All code blocks have copy button
hideLineNumbers: false, // Show line numbers by default
copiedLabel: 'Copied!', // Customize copy button labels
copyLabel: 'Copy',
});
function App() {
return <MuiMarkdown overrides={overrides}>{markdownContent}</MuiMarkdown>;
}Customization
All visual elements can be customized using MUI theming.
Custom colors
const overrides = getOverrides({
Highlight,
themes,
highlightColor: 'primary.main', // Use theme colors
removedColor: 'error.dark',
insertedColor: 'success.light',
});Custom copy button icons
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
import CheckIcon from '@mui/icons-material/Check';
const overrides = getOverrides({
Highlight,
themes,
copyIcon: <ContentCopyIcon />,
copiedIcon: <CheckIcon />,
copyButtonSx: { top: 16, right: 16 }, // Custom positioning
});Custom copy component
For complete control over the copy button, provide your own component:
import { CopyComponentProps } from 'mui-markdown';
import { IconButton } from '@mui/material';
const CustomCopyButton = ({ handleCopy, code }: CopyComponentProps) => {
return (
<IconButton
onClick={handleCopy}
sx={{ position: 'absolute', top: 8, right: 8 }}
>
Copy {code.split('\n').length} lines
</IconButton>
);
};
const overrides = getOverrides({
Highlight,
themes,
CopyComponent: CustomCopyButton,
});Custom file name display
import FolderIcon from '@mui/icons-material/Folder';
const overrides = getOverrides({
Highlight,
themes,
showFileIcon: true, // Show/hide icon
fileIcon: <FolderIcon />, // Custom icon
FileNameComponent: CustomTypography, // Custom component
fileNameSx: { fontWeight: 'bold' }, // Custom text styles
fileNameWrapperSx: { backgroundColor: 'primary.light', px: 3 },
useHighlightThemeBackground: true, // Prism theme background for file name wrapper
});Diagram Support (Mermaid)
mui-markdown uses mermaid as its diagramming and charting tool. First make sure mermaid is installed, then enable with enableMermaid and provide the Diagram component. Configure via mermaidConfig.
App.tsximport React from 'react';
import { MuiMarkdown, getOverrides } from 'mui-markdown';
import { Diagram } from 'mui-markdown/client'; // Handles mermaid init and content load
import { Highlight, themes } from 'prism-react-renderer';
const App = () => {
return (
<MuiMarkdown
enableMermaid
mermaidConfig={{ startOnLoad: true }}
DiagramComponent={Diagram}
>
{/* Markdown content */}
</MuiMarkdown>
);
};
export default App;The Diagram component is a client-side component. You can create your own — it just needs to satisfy (props: DiagramProps) => JSX.Element. The props type is available under mui-markdown and mui-markdown/client.
Math Support (KaTeX)
mui-markdown uses katex to render math blocks. It's an optional dependency, so install it first:
# with npm npm i katex # with yarn yarn add katex
Then enable with the enableMath prop and pass the MathBlock component (or your own satisfying (props: MathBlockProps) => JSX.Element). Don't forget the KaTeX stylesheet.
App.tsximport React from 'react';
import { MuiMarkdown } from 'mui-markdown';
import { MathBlock } from 'mui-markdown/client'; // Lazy-loads katex on the client
import 'katex/dist/katex.min.css';
const App = () => {
return (
<MuiMarkdown enableMath MathComponent={MathBlock}>
{`
\`\`\`math
E = mc^2
\`\`\`
`}
</MuiMarkdown>
);
};
export default App;Math blocks are written as fenced code blocks with the math language. Pass KaTeX options via katexOptions. Without enableMath, math blocks render as regular code blocks — nothing changes unless you opt in.
Table of Contents Extraction
Use extractHeadings to get the list of headings (text, level, and the same anchor id that MuiMarkdown renders) and build your own table of contents:
App.tsximport React from 'react';
import { Link, List, ListItem } from '@mui/material';
import { MuiMarkdown, extractHeadings } from 'mui-markdown';
const markdown = `
# Getting Started
## Installation
## Usage
`;
const App = () => {
const headings = extractHeadings(markdown);
return (
<>
<List>
{headings.map((heading) => (
<ListItem key={heading.id} sx={{ pl: heading.level * 2 }}>
<Link href={`#${heading.id}`}>{heading.text}</Link>
</ListItem>
))}
</List>
<MuiMarkdown>{markdown}</MuiMarkdown>
</>
);
};
export default App;extractHeadings is a pure function (no rendering), so you can also use it on the server or at build time.Next.js
Use with useMDXComponents
To add mui-markdown to useMDXComponents, either import defaultMdxComponents or use getMdxComponents if you need to override defaults.
mdx-components.tsimport type { MDXComponents } from 'mdx/types';
import { defaultMdxComponents, getMdxComponents } from 'mui-markdown';
// Use getMdxComponents(options) to override defaults!
// const mdxComponents = getMdxComponents();
export function useMDXComponents(components: MDXComponents): MDXComponents {
return {
// ...mdxComponents,
...defaultMdxComponents,
...components,
};
}






