Link to the code that reproduces this issue
https://github.com/ProchaLu/next-js-mdx-provider
CodeSandbox
To Reproduce
- Clone repro,
git clone https://github.com/ProchaLu/next-js-mdx-provider
- install dependencies
- run development server
Current vs. Expected behavior
I'm trying to use both mdx-components.tsx and MDXProvider together (like the nested MDXProvider pattern). Our constraints are as follows:
-
our app is large with multiple areas - different areas should receive different MDX components
-
we are trying to avoid prop drilling - having to pass components={props.components} in every MDX file where we import another MDX file, eg. trying to avoid this:
import Child from './child.mdx'
{/* Trying to avoid this */}
<Child components={props.components} />
Current Behavior
When using the MDXProvider in MDXComponent.tsx to provide custom components (h3 and h4), these components are not applied to the MDX content. Instead, only the global components defined in mdx-components.tsx (for h1 and h2) are applied.
mdx-components.tsx
const components = {
h1: ({ children, ...props }: HTMLAttributes<HTMLHeadElement>) => (
<h1 style={{ color: 'tomato' }} {...props}>
{children}
</h1>
),
h2: ({ children, ...props }: HTMLAttributes<HTMLHeadElement>) => (
<h2 style={{ color: 'blue' }} {...props}>
{children}
</h2>
),
} satisfies MDXComponents;
declare global {
type MDXProvidedComponents = typeof components;
}
// eslint-disable-next-line no-undef
export function useMDXComponents(): MDXProvidedComponents {
return components;
}
MDXComponent.tsx
'use client';
import { MDXProvider } from '@mdx-js/react';
import { MDXComponents } from 'mdx/types';
import { HTMLAttributes } from 'react';
import Content from './message.mdx';
const components = {
h3: ({ children, ...props }: HTMLAttributes<HTMLHeadElement>) => (
<h3 style={{ color: 'purple' }} {...props}>
{children}
</h3>
),
h4: ({ children, ...props }: HTMLAttributes<HTMLHeadElement>) => (
<h4 style={{ color: 'yellow' }} {...props}>
{children}
</h4>
),
} satisfies MDXComponents;
export default function MDXComponent() {
return (
<MDXProvider components={components}>
<Content />
</MDXProvider>
);
}
Expected Behavior
The MDXProvider in MDXComponent.tsx should apply its locally defined custom components (h3 and h4) to the MDX content.
- h1 and h2 should get their styles from the global
mdx-components.tsx.
- h3 and h4 should get their styles from the local
MDXProvider in MDXComponent.tsx.
This would allow for a more flexible and modular approach where different sections of the application can have different MDX component configurations without the need for prop drilling or defining all components globally.
However, it appears that this is not supported in the Next.js MDX integration:
Are there any suggestions for providing custom MDX components in different app areas without manually prop drilling?
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 23.5.0: Wed May 1 20:19:05 PDT 2024; root:xnu-10063.121.3~5/RELEASE_ARM64_T8112
Available memory (MB): 16384
Available CPU cores: 8
Binaries:
Node: 20.16.0
npm: 10.8.1
Yarn: N/A
pnpm: 9.4.0
Relevant Packages:
next: 14.2.7 // Latest available version is detected (14.2.7).
eslint-config-next: N/A
react: 18.2.0
react-dom: 18.2.0
typescript: 5.5.2
Next.js Config:
output: N/A
Which area(s) are affected? (Select all that apply)
Markdown (MDX)
Which stage(s) are affected? (Select all that apply)
next dev (local), next build (local), next start (local)
Additional context
No response
Link to the code that reproduces this issue
https://github.com/ProchaLu/next-js-mdx-provider
CodeSandbox
To Reproduce
git clone https://github.com/ProchaLu/next-js-mdx-providerCurrent vs. Expected behavior
I'm trying to use both
mdx-components.tsxandMDXProvidertogether (like the nestedMDXProviderpattern). Our constraints are as follows:our app is large with multiple areas - different areas should receive different MDX
componentswe are trying to avoid prop drilling - having to pass
components={props.components}in every MDX file where we import another MDX file, eg. trying to avoid this:Current Behavior
When using the MDXProvider in
MDXComponent.tsxto provide custom components (h3 and h4), these components are not applied to the MDX content. Instead, only the global components defined inmdx-components.tsx(for h1 and h2) are applied.mdx-components.tsxMDXComponent.tsxExpected Behavior
The
MDXProviderinMDXComponent.tsxshould apply its locally defined custom components (h3 and h4) to the MDX content.mdx-components.tsx.MDXProviderinMDXComponent.tsx.This would allow for a more flexible and modular approach where different sections of the application can have different MDX component configurations without the need for prop drilling or defining all components globally.
However, it appears that this is not supported in the Next.js MDX integration:
Are there any suggestions for providing custom MDX
componentsin different app areas without manually prop drilling?Provide environment information
Operating System: Platform: darwin Arch: arm64 Version: Darwin Kernel Version 23.5.0: Wed May 1 20:19:05 PDT 2024; root:xnu-10063.121.3~5/RELEASE_ARM64_T8112 Available memory (MB): 16384 Available CPU cores: 8 Binaries: Node: 20.16.0 npm: 10.8.1 Yarn: N/A pnpm: 9.4.0 Relevant Packages: next: 14.2.7 // Latest available version is detected (14.2.7). eslint-config-next: N/A react: 18.2.0 react-dom: 18.2.0 typescript: 5.5.2 Next.js Config: output: N/AWhich area(s) are affected? (Select all that apply)
Markdown (MDX)
Which stage(s) are affected? (Select all that apply)
next dev (local), next build (local), next start (local)
Additional context
No response