I'm trying to figure out why I have to specify all HTML tags in the gatsby-browser.js in order for the MDXrenderer to understand how to style the HTML tags.
The content comes from GraphCMS via GraphQL queries.
I've been looking into other gatsby projects, where the specifications are not set, but they render HTML tags correctly.
I was able to target most HTML tags, but I cannot figure out how my "ul" and "li" tags get rendered. I'm able to target them and apply colors for instance, but it still looks like a "p" tag on the page when viewing. Though if you inspect the element it does show "ul" and "li" tags.
See the example below:
Here is my gatsby-node.js file:
const path = require("path")
exports.createPages = async ({ actions: { createPage }, graphql }) => {
const { data } = await graphql(
`
{
pages: allGraphCmsPage {
nodes {
id
content {
markdownNode {
childMdx {
body
}
}
}
seo {
description
image {
url
}
keywords
title
}
slug
subtitle
title
}
}
posts: allGraphCmsPost(sort: { fields: date, order: ASC }) {
edges {
nextPost: next {
slug
title
}
page: node {
id
author {
id
name
title
}
content {
markdownNode {
childMdx {
body
}
}
}
date: formattedDate
excerpt
seo {
description
image {
url
}
keywords
title
}
slug
title
}
previousPost: previous {
slug
title
}
}
}
}
`
)
if (data.errors) throw data.errors
data.posts.edges.forEach(({ nextPost, page, previousPost }) => {
createPage({
component: path.resolve("./src/templates/article-post.tsx"),
context: {
id: page.id,
page,
previousPost,
nextPost,
},
path: `/articles/${page.slug}`,
})
})
data.pages.nodes.forEach(page => {
createPage({
component: path.resolve("./src/templates/default-page.tsx"),
context: {
page,
},
path: `/${page.slug}`,
})
})
}
exports.createResolvers = ({ createResolvers }) => {
const resolvers = {
GraphCMS_Post: {
formattedDate: {
type: "String",
resolve: source => {
const date = new Date(source.date)
return new Intl.DateTimeFormat("en-US", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
}).format(date)
},
},
},
}
createResolvers(resolvers)
}
Here is my gatsby-config.js file:
require("dotenv").config()
const path = require("path")
module.exports = {
siteMetadata: {
title: `Code Shape`,
description: `Learn to create great things.`,
author: `@codeshape`,
},
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/static/images/icons`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/static/images/logos`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/static/images/profiles`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `posts`,
path: `${__dirname}/src/posts/`,
},
},
{
resolve: "gatsby-plugin-page-creator",
options: {
path: `${__dirname}/src/posts`,
},
},
`gatsby-plugin-mdx`,
{
resolve: "gatsby-source-graphcms",
options: {
endpoint: process.env.GRAPHCMS_ENDPOINT,
token: process.env.GRAPHCMS_TOKEN,
buildMarkdownNodes: true,
downloadLocalImages: true,
},
},
`gatsby-plugin-styled-components`,
`gatsby-plugin-react-helmet`,
"gatsby-transformer-sharp",
"gatsby-plugin-sharp",
],
}
Here is my gatsby-browser.js file:
import React from "react"
import { MDXProvider } from "@mdx-js/react"
import Layout from "./src/components/layout/layout"
/* eslint-disable */
const components = {
wrapper: ({ children }) => <>{children}</>,
h1: props => (
<h1 style={{ fontSize: "60px", fontWeight: "bold" }} {...props} />
),
h2: props => (
<h2 style={{ fontSize: "40px", fontWeight: "bold" }} {...props} />
),
h3: props => (
<h3 style={{ fontSize: "30px", fontWeight: "bold" }} {...props} />
),
h4: props => (
<h4 style={{ fontSize: "20px", fontWeight: "bold" }} {...props} />
),
p: props => <p style={{ fontSize: "16px", lineHeight: 1.6 }} {...props} />,
strong: props => (
<strong style={{ fontWeight: "900", lineHeight: 1.6 }} {...props} />
),
img: props => <img style={{ width: "100%" }} {...props} />,
pre: props => {
const className = props.children.props.className || ""
const matches = className.match(/language-(?<lang>.*)/)
return (
<Highlight
{...defaultProps}
code={props.children.props.children}
language={
matches && matches.groups && matches.groups.lang
? matches.groups.lang
: ""
}
>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre className={className} style={style}>
{tokens.map((line, i) => (
<div {...getLineProps({ line, key: i })}>
{line.map((token, key) => (
<span {...getTokenProps({ token, key })} />
))}
</div>
))}
</pre>
)}
</Highlight>
)
},
}
const wrapPageElement = ({ element, props }) => (
<Layout {...props}>{element}</Layout>
)
const wrapRootElement = ({ element }) => (
<MDXProvider components={components}>{element}</MDXProvider>
)
export { wrapPageElement, wrapRootElement }
And here is the template for my article-post.tsx file:
import React from "react"
import { graphql, Link } from "gatsby"
import Img from "gatsby-image"
import { MDXRenderer } from "gatsby-plugin-mdx"
import styled from "styled-components"
import {
BodyMain,
Caption,
H1,
MediumText,
} from "../components/styles/TextStyles"
import ReactDisqusComments from "react-disqus-comments"
import LazyLoad from "react-lazy-load"
export const pageQuery = graphql`
fragment AssetFields on GraphCMS_Asset {
id
localFile {
childImageSharp {
fluid(maxWidth: 600) {
...GatsbyImageSharpFluid
}
}
}
}
query ArticlePostQuery($id: String!) {
authorImage: graphCmsAsset(
authorAvatar: {
elemMatch: { posts: { elemMatch: { id: { in: [$id] } } } }
}
) {
...AssetFields
}
coverImage: graphCmsAsset(
coverImagePost: { elemMatch: { id: { eq: $id } } }
) {
...AssetFields
}
}
`
export default function ArticlePostTemplate({
data: { authorImage, coverImage },
pageContext: { nextPost, page, previousPost },
}) {
return (
<Wrapper>
<Header>
<PublishDate>{page.date}</PublishDate>
<PageTitle>{page.title}</PageTitle>
</Header>
<InformationWrapper>
<AuthorWrapper>
<AuthorAvatar>
<Img
fluid={authorImage.localFile.childImageSharp.fluid}
fadeIn={false}
className="Image"
/>
</AuthorAvatar>
<AuthorTextWrapper>
<AuthorName>{page.author.name}</AuthorName>
<AuthorTitle>{page.author.title}</AuthorTitle>
</AuthorTextWrapper>
</AuthorWrapper>
</InformationWrapper>
<ContentWrapper>
<Img
fluid={coverImage.localFile.childImageSharp.fluid}
fadeIn={false}
className="CoverImage"
/>
<MDXRenderer>{page.content.markdownNode.childMdx.body}</MDXRenderer>
</ContentWrapper>
<Navigation>
{(nextPost || previousPost) && (
<div>
<hr className="Divider" />
{nextPost && (
<div>
<h2>Next Post</h2>
<div>
<Link to={`/articles/${nextPost.slug}`}>
{nextPost.title}
</Link>
</div>
<hr className="Divider" />
</div>
)}
{previousPost && (
<div>
<h2>Previous Post</h2>
<div>
<Link to={`/articles/${previousPost.slug}`}>
{previousPost.title}
</Link>
</div>
<hr className="Divider" />
</div>
)}
</div>
)}
<div>
<Link to="/articles/" className="">
← Back to the blog
</Link>
</div>
</Navigation>
<LazyLoad offsetTop={400}>
<ReactDisqusComments
shortname="codeshape"
identifier={page.id}
title={page.title}
url={page.url}
category_id={page.category_id}
/>
</LazyLoad>
</Wrapper>
)
}
const Wrapper = styled.div`
margin: 1.875rem;
display: grid;
grid-gap: 1.875rem;
`
const Header = styled.div`
text-align: center;
margin: 0 auto;
`
const PublishDate = styled(BodyMain)`
color: #757372;
`
const PageTitle = styled(H1)``
const InformationWrapper = styled.div`
display: grid;
align-items: center;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
`
const ContentWrapper = styled.div`
display: grid;
grid-gap: 1rem;
margin: 0 auto;
max-width: 80rem;
.CoverImage {
border-radius: 1.25rem;
object-fit: cover;
}
`
const AuthorWrapper = styled.div`
margin: 0 auto;
padding: 1rem;
display: grid;
grid-gap: 1rem;
grid-template-columns: auto auto;
width: 20rem;
justify-content: center;
align-content: center;
`
const AuthorAvatar = styled.div`
.Image {
border-radius: 50%;
border: 3px solid white;
width: 4rem;
}
`
const AuthorTextWrapper = styled.div`
display: grid;
justify-content: center;
align-content: center;
`
const AuthorName = styled(MediumText)`
font-weight: 900;
`
const AuthorTitle = styled(Caption)`
color: #757372;
`
const Navigation = styled.div`
margin: 0 auto;
text-align: center;
padding: 1.875rem;
display: grid;
grid-gap: 1rem;
width: 18rem;
.Divider {
color: #757372;
line-height: 3rem;
}
`
Dependencies in package.json file:
"@mdx-js/mdx": "^1.6.22",
"@mdx-js/react": "^1.6.22",
"@types/react-helmet": "^6.1.0",
"@types/styled-components": "^5.1.4",
"autoprefixer": "^10.2.3",
"babel-plugin-styled-components": "^1.12.0",
"gatsby": "^2.28.0",
"gatsby-image": "^2.10.0",
"gatsby-plugin-manifest": "^2.8.0",
"gatsby-plugin-mdx": "^1.9.0",
"gatsby-plugin-offline": "^3.6.0",
"gatsby-plugin-react-helmet": "^3.6.0",
"gatsby-plugin-sharp": "^2.13.4",
"gatsby-plugin-styled-components": "^3.9.0",
"gatsby-source-filesystem": "^2.7.0",
"gatsby-source-graphcms": "^2.2.0",
"gatsby-transformer-sharp": "^2.11.0",
"prop-types": "^15.7.2",
"react": "^16.14.0",
"react-disqus-comments": "^1.4.0",
"react-dom": "^16.14.0",
"react-helmet": "^6.1.0",
"react-lazy-load": "^3.1.13",
"styled-components": "^5.2.1"
},
Can you help me with what I need to do in order for MDXrenderer to work? I still need to figure out how lists and code blocks get rendered.
You are overkilling completely the issue. You don't need to create an instance in the
gatsby-browser.js
to "make the MDX understand". Your MDX is working perfectly since you are rendering an<ul>
and<li>
. You are only missing the styles.In the screenshot, you've shared, can be seen the following:
This is making your lists to "looks like a
<p>
".You just need to add the correct styles to them or removing the resetting styles. By default, the
<ul>
has:And the
<li>
:Once you restored the default styling, your list tags will look as they are.