
NextJS with MDX
npm install @next/mdx @mdx-js/loader @mdx-js/react @types/mdx
next.config.ts
import createMDX from "@next/mdx";
/** @type {import('next').NextConfig} */
const nextConfig = {
// Configure `pageExtensions` to include markdown and MDX files
pageExtensions: ["js", "jsx", "md", "mdx", "ts", "tsx"],
// Optionally, add any other Next.js config below
};
const withMDX = createMDX({
// Add markdown plugins here, as desired
extension: /\.(md|mdx)$/,
});
// Merge MDX config with Next.js config
export default withMDX(nextConfig);
src/mdx-components.tsx
import type { MDXComponents } from "mdx/types";
const components: MDXComponents = {};
export function useMDXComponents(): MDXComponents {
return components;
}
Typography (Optional)
npm install -D @tailwindcss/typography
tailwind.config.js
import typography from "@tailwindcss/typography";
const config = {
theme: {
// ...
},
plugins: [
typography,
// ...
],
};
export default config;
src/app/global.css
@plugin "@tailwindcss/typography";
shiki (Optional)
npm install -D shiki
src/components/code.tsx
import { codeToHtml } from "shiki";
import type { BundledLanguage, BundledTheme } from "shiki";
type Props = {
code: string;
lang?: BundledLanguage;
theme?: BundledTheme;
};
export async function Code({
code,
lang = "javascript",
theme = "nord",
}: Props) {
const html = await codeToHtml(code, {
lang,
theme,
});
return <div dangerouslySetInnerHTML={{ __html: html }}></div>;
}
src/mdx-components.tsx
import type { MDXComponents } from "mdx/types";
import React from "react";
import { Code } from "./components/code";
const components: MDXComponents = {
pre: async ({ children }) => {
const codeElement = React.Children.only(children);
const lang = codeElement.props.className.split("-")[1];
return (
<Code code={codeElement.props.children} lang={lang} theme="github-dark" />
);
},
};
export function useMDXComponents(): MDXComponents {
return components;
}