Hi,
I'm using gatsby-plugin-mdx to add rich markdown to my site.
I want to access the frontmatter of the markdown within the markdown itself.
The docs say this is available in my MDX file with {props.pageContext.frontmatter} but this returns an error "TypeError: Cannot read property 'frontmatter' of undefined".
I presume this is because, rather than rendering as an individual page, I'm trying to render this mardown inside a component using MDXRenderer. I'm guessing that in this case "props.pageContext..." doesn't work.
(The actual use case is for a portfolio site - I'm trying to loop through all my "Work" markdown files on a single "Featured Work" page and render each one individually)
I expect that the way to do this is by passing the a variable using the MDXRenderer component. Something like:
<MDXRenderer category={work.frontmatter.category}>{work.body}</MDXRenderer>
But then I'm not sure how to access the category property inside my MDX markdown.
Is this the correct way to pass variables into my MDX code? Is what I want to do even possible? And if so, how do I then access the variables inside my MDX file?
Thanks in advance,
B
The actual use case is for a portfolio site - I'm trying to loop through all my "Work" markdown files on a single "Featured Work" page and render each one individually
If I understand you correctly, isn't this what you want to do?
https://www.gatsbyjs.org/docs/mdx/programmatically-creating-pages/#bonus-make-a-blog-index
Query all mdx data and display it?
Hi
Thanks for getting back to me.
This is close - and I've got something similar to this working fine.
But what I really want to be able to do is to access the frontmatter variables from _inside_ my MDX markdown. The reason being is I'd like to slightly customise my layout and components on a post by post basis by changing markdown.
The docs suggest this is possible. But this method isn't working for me.
Can you provide a minimal reproduction?
We'd highly appreciate that!
I can do that yes but just in case I'm able to save a bit of time by describing my case in a bit more depth here I will just do that first if that's OK - I don't think this is a bug - I just think there's something I'm not quite getting about the way MDX works:
I have a graphql query that returns all the "Featured Work" mdx files. This site is for a music producer. So each Featured Work post is an artist the producer has worked with. In the frontmatter for each post is the artist name, social links etc.
const data = useStaticQuery(graphql`
query {
allMdx(filter: {frontmatter: {type: {eq: "featuredWork"}}}) {
nodes {
id
frontmatter {
genre
artist
socials {
spotify
instagram
facebook
twitter
soundcloud
}
spotifyEmbed
title
}
excerpt
body
}
}
}
)
I then loop through data.allMdx.nodes, and pass the content through to a "Featured Work" component.
const featuredWorkData = data.allMdx.nodes
{featuredWorkData.map((work, index) => <FeaturedWork work={work} key={work.id} index={index} /> )}
My FeaturedWork component looks something like this:
const featuredWork = ({work, index}) => {
return (
<>
<FeaturedWorkContent className={featuredWorkStyles.featuredWorkContent}>
<h3>{work.frontmatter.genre}</h3>
<h2>{work.frontmatter.artist}</h2>
<MDXRenderer>{work.body}</MDXRenderer>
</>
)
}
export default featuredWork
This is all working just great. It reads the mdx files just fine.
But - you see how I added "socials" in my frontmatter - I would love to be able to create a component called "SocialLinks" that renders out some social media links and have the option of inserting this _inside my .mdx markdown_
I'm able to add components in my markdown:
import {SocialLinks} from '../../components/miscBJComponents'
Lorem Ipsum ...
<SocialLinks />
This will output the content of the component if it's a simple static component.
But I need to pass the frontmatter data to it.
Something like
---
"socials": {
"spotify": "https://open.spotify.com/artist/6jCJXKWlZky694nYGcJlm1?si=NUKotT5jR5OYBRCx3dUKiQ",
"instagram":"https://www.instagram.com/childcareband",
"facebook":"https://www.facebook.com/childcareband",
"twitter":"https://www.twitter.com/childcareband",
"soundcloud":"https://soundcloud.com/childcare",
}
---
import {SocialLinks} from '../../components/miscBJComponents'
Lorem Ipsum ...
<SocialLinks links={frontmatter.socials} />
I've tried using {props.pageContext.frontmatter.socials} as it says in the docs. But I get an error - "TypeError: Cannot read property 'frontmatter' of undefined".
I presumed there was something I could do like
<MDXRenderer frontmatter={work.frontmatter}>{work.body}</MDXRenderer>
And I still suspect this might be the case - but what I'm not sure of is how you access those passed variables from _within the markdown body._
Apologies for the long reply. I hope that makes sense. Let me know if you'd like anything clarified.
Thanks again,
Ben
Update:
After doing more searching I've found this thread on Spectrum that explained that any properties passed in
e.g. in my case I can do
<MDXRenderer frontmatter={work.frontmatter}>{work.body}</MDXRenderer>
and then in the mdx markup I can add a component and use the {props} object. E.g.
<Socials links={props.frontmatter.socials}/>
Funny, I could have sworn I tried that while I was debugging but apparently not well enough.
Update:
After doing more searching I've found this thread on Spectrum that explained that any properties passed in are available in the {props} object in the mdx file.
e.g. in my case I can do
<MDXRenderer frontmatter={work.frontmatter}>{work.body}</MDXRenderer>and then in the mdx markup I can add a component and use the {props} object. E.g.
<Socials links={props.frontmatter.socials}/>Funny, I could have sworn I tried that while I was debugging but apparently not well enough.
Thx for the solution! That's working!
How to suggest add this code to the official docs?
<MDXRenderer frontmatter={work.frontmatter}>{work.body}</MDXRenderer>
I still don't see this information in the official docs, and it confused me until I find this thread. Mind I ask if I may add this as documentation for mdx in the Programmatically creating pages section as suggested by n-laverenko? I think it would help a lot of people.
Most helpful comment
Update:
After doing more searching I've found this thread on Spectrum that explained that any properties passed in are available in the {props} object in the mdx file.
e.g. in my case I can do
<MDXRenderer frontmatter={work.frontmatter}>{work.body}</MDXRenderer>and then in the mdx markup I can add a component and use the {props} object. E.g.
<Socials links={props.frontmatter.socials}/>Funny, I could have sworn I tried that while I was debugging but apparently not well enough.