Custom wrapper component does not receive actual MDX content in props.children when using app router
Link to the code that reproduces this issue
https://github.com/LudoLogical/next-mdx-custom-wrapper-demo
To Reproduce
-
npx create-next-app@latest -e reproduction-template -
Follow the steps from App Router > Building Your Application > Configuring > MDX in the docs:
-
npm install @next/mdx @mdx-js/loader @mdx-js/react @types/mdx -
Create
/mdx-components.tsxand add the following:import type { MDXComponents } from 'mdx/types' export function useMDXComponents(components: MDXComponents): MDXComponents { return { ...components, } } -
Change
/next.config.jsto read as follows:const withMDX = require('@next/mdx')() /** @type {import('next').NextConfig} */ const nextConfig = { // Configure `pageExtensions` to include MDX files pageExtensions: ['js', 'jsx', 'mdx', 'ts', 'tsx'], // Optionally, add any other Next.js config below } module.exports = withMDX(nextConfig) -
Create
/app/test/page.mdxand add the following:# Welcome to my MDX page! This is some **bold** and _italics_ text. This is a list in markdown: - One - Two - Three
-
-
Edit
/mdx-components.tsxto add a custom component definition forwrapper:import { type ReactElement, type ReactNode } from "react"; import type { MDXComponents } from "mdx/types"; export function useMDXComponents(components: MDXComponents): MDXComponents { return { wrapper: ({ children }: { children: ReactNode }) => { console.log(children); console.log((children as ReactElement).props.children); return children; }, ...components, }; } -
npm run devand navigate tolocalhost:3000/test
Current vs. Expected behavior
Current
The following is the result of the first console.log():
{
'$$typeof': Symbol(react.element),
type: [Function: _createMdxContent],
key: null,
ref: null,
props: { params: {}, searchParams: {} },
_owner: null,
_store: {}
}
The second console.log() outputs undefined.
Expected
The behavior shown in "The X in MDX," a short talk by Rodrigo Pombo on the Vercel YouTube channel. Note that the talk concerns the pages router, but the equivalent behavior is highly desirable in app router so that the effect that Pombo creates can be replicated. The console output should be something like what Pombo shows here - i.e., it should be possible to manipulate the ReactElements generated from the input MDX to, for example, create a table of contents from the headers.
Verify canary release
- [X] I verified that the issue exists in the latest Next.js canary release
Provide environment information
Operating System:
Platform: linux
Arch: x64
Version: #1 SMP Fri Jan 27 02:56:13 UTC 2023
Binaries:
Node: 20.9.0
npm: 10.1.0
Yarn: 1.22.21
pnpm: 8.10.5
Relevant Packages:
next: 14.0.4-canary.17
eslint-config-next: N/A
react: 18.2.0
react-dom: 18.2.0
typescript: 5.1.3
Next.js Config:
output: N/A
Which area(s) are affected? (Select all that apply)
App Router, MDX (@next/mdx)
Additional context
Current workarounds:
- For some use cases, you can write custom
remarkand/orrehypeplugins as detailed here - You can wrap an imported
<MyMDXContent />ReactElementin adivand apply a callback ref in which you either manipulate theElements directly or set auseState()variable whose contents are rendered if they exist with newReactElement(s). (Of course,useEffect()with an empty dependency array can also be used to achieve this, but there can be some problems with that approach.)
Notably absent from this list is the use of a layout.tsx file, as console.log()ing the children prop there produces the same output shown in the "Current vs. Expected behavior" section above. The issue stems from the fact that the translation from MDX to React code has not yet taken place.
Possibly related reading (the potential fixes discussed within do not resolve this issue):
- https://github.com/vercel/next.js/discussions/50897
- https://github.com/vercel/next.js/issues/57976
+1
Edit by maintainers: Comment was automatically minimized because it was considered unhelpful. (If you think this was by mistake, let us know). Please only comment if it adds context to the issue. If you want to express that you have the same problem, use the upvote 👍 on the issue description or subscribe to the issue for updates. Thanks!
Seems to have changed between v14.0.3 and v14.0.4, it was working for me with v14.0.3.
Running into exactly the same issue. Following the steps from the tutorial and then trying to manipulate/read children in the wrapper returns no usable result.
Our use case is reading the content and creating a table of content for all heading elements.
Did you find any solution for this?
I can confirm it works in v14.0.3. We were using 14.2.0-canary.0 where it definitely doesn't work.
Also not working in v14.1.3 after following docs
Hi folks! Someone has a solution with the app router to get the TOC ?