- Published on
Using Horizontal Overflow for katex in mdx-bundler
- Authors
- Name
- adyingdeath
- @adyingdeath
Recently, I encountered an issue while using katex
with mdx-bundler
:
The math block may overflow on mobile devices. There isn't a direct way to add overflow-x: auto
to the katex block.
After some researches, I found the solution and would like to take a note here.
Below is my method for implementing math rendering in MDX on my website. If your setup differs from mine, you might need to adjust the code accordingly.
- Install
mdx-bundler
andreact-katex
. - Add
remark-math
andrehype-katex
as plugins formdx-bundler
.
To solve the overflow problem, I wrapped the .katex-display
element in a custom div
with the style overflow-x: auto;
.
My Original Code
// page.tsx
"use client";
import { useMemo } from 'react';
import { getMDXComponent } from 'mdx-bundler/client';
import { getMdxContent } from '@/app/global';
import 'katex/dist/katex.min.css';
export default async function Page() {
const srcPath = "path of mdx file";
const mdxSource = await getMdxContent(srcPath);
const Component = useMemo(() => getMDXComponent(mdxSource), [mdxSource]);
return (
<Component />
);
}
// global.ts
import { bundleMDX } from 'mdx-bundler';
import fs from 'fs';
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';
export async function getMdxContent(src: string) {
const source = fs.readFileSync(src, 'utf8');
const { code } = await bundleMDX({
source,
mdxOptions(options) {
options.remarkPlugins = [...(options.remarkPlugins ?? []), remarkMath];
options.rehypePlugins = [...(options.rehypePlugins ?? []), rehypeKatex];
return options;
},
});
return code;
}
The rehype-katex
plugin is used to transform math formulas into HTML code. I created a custom rehype plugin that works after rehype-katex
and wraps all .katex-display
elements with a custom div.
Solution
You can copy the plugin's code below. First, you need to install these libraries for plugin development:
npm install unified unist-util-visit hast
Next, copy and paste this function into your source code. You can place it anywhere; for example, here I put it directly in global.ts
.
// global.ts
/* other imports */
import { Plugin } from 'unified';
import { visit } from 'unist-util-visit';
import { Element, Parent } from 'hast';
const rehypeWrapMathBlock: Plugin = () => {
return (tree) => {
visit(tree, 'element', (node: Element, index, parent: Parent) => {
if (node.properties && node.properties.className) {
const classList = node.properties.className as string[];
if (classList.includes('katex-display')) {
const wrapper: Element = {
type: 'element',
tagName: 'div',
properties: {
style: "overflow-x: auto;"
},
children: [node]
};
parent.children[index] = wrapper;
}
}
});
};
};
/* other codes */
Next, incorporate it as a mdx-bundler
plugin. If rehypeWrapMathBlock
is not in the same file as getMdxContent
function, you should import it first. The following code snippet is modified based on code from the previous section (click here to jump):
// Add "rehypeWrapMathBlock" after "rehypeKatex"
options.rehypePlugins = [...(options.rehypePlugins ?? []), rehypeKatex, rehypeWrapMathBlock];
This will now wrap the original .katex-display
DOM element with a <div style="overflow-x: auto;"></div>
.