BLOG
ARTICLE

How to Unwrap Image Tag in Markdown

2 min read

Why did I write this?

Update February 23: I have since abandoned MDX in favor of react-markdown. Keep reading for details!

If you have tried Markdown to generate a blog article, you probably have encountered the bizarre behavior of having image tag wrapped under paragraph tag.

I'm talking about something like this:

1
2
3
4
5
6
7
8
9
<p>
    Sentence 1
</p>
<p>
    <img />
</p>
<p>
    Sentence 2
</p>

I could not help but feel discomfort upon seeing that. Yet unfortunately, that is the default behavior of Markdown. If we want to do something advanced, such as having the image bleed out from its grid container, we need to unwrap the image tag from below the paragraph tag. I'm specifically writing this guide for Next.Js, but I imagine it would not be too different for other React frameworks like Gatsby.

Why did I abandon MDX?

While working with MDX I ended up using next-mdx-remote to load MDX files in Next.Js getStaticProps and hydrate in client. It worked. However, the bundle size bloated due to hydrate being included in client. It should not be happening, yet after spending hours I could not find out how to fix it. Thus I said goodbye to MDX. (If I did it the wrong way though, let me know here!) .

The new implementation

Enter react-markdown. I found this markdown package easier to configure than MDX.

  1. First, install react-markdown
1
npm install react-markdown
  1. Then import it and place in your code. I put it in my blog post body PostBody.js component, as shown below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import ReactMarkdown from 'react-markdown';

function Component({ content }) {
    const renderers = {
        // Make your custom renderers here
    }

    return (
        <ReactMarkdown
            renderers={renderers}
            children={content}
        />
    )
}
  1. Next, install remark-unwrap-images remark plugin.
1
npm install remark-unwrap-images
  1. After that modify ReactMarkdown in component by adding the plugin
1
2
3
4
5
6
7
8
9
return (
        <ReactMarkdown
            renderers={renderers}
            children={content}
            plugins={[
                unwrapImages
            ]}
        />
    )

The result

And that's it. Voila! The paragraph tag is gone from our Markdown images. And I could do what I wanted: a bleeding image spanning grid columns. Just like the image below.

1
2
3
<div class="className">
    <img />
</div>
Tap to enlarge this image 👇
01.jpg

The old way

I preserve the writing as-is here.

First, install a plugin. John Otander has written a handy plugin remark-unwrap-images to unwrap the image tag.

I have read many instructions to put the plugin in next.config.js, something like this:

1
2
3
4
5
6
7
const withMDX = require('@next/mdx')({
  options: {
    remarkPlugins: [],
    rehypePlugins: []
  }
})
module.exports = withMDX()

Note: You would need to install @next/mdx package as well here.

Too bad this does not work for me as I'm using next-compose-plugins in my next.config.js. Something in the configuration must be stopping remark-unwrap-images from working. I spent some time trying to figure out the right combination of plugins (or their order) to no avail.

Then I found out I could just shove in the plugin under a custom js file that I used to convert MDX to string and vice-versa via next-mdx-remote.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import renderToString from 'next-mdx-remote/render-to-string';
import unwrapImages from 'remark-unwrap-images';

...

export function mdxToString(mdx) {
    // return renderToString(mdx, { components });
    return renderToString(mdx, {
        mdxOptions: {
            remarkPlugins: [
                unwrapImages
            ],
        }
    });
}
Jerfareza Daviano

Hi, I'm Jerfareza
Daviano 👋🏼

Hi, I'm Jerfareza Daviano 👋🏼

I'm a Full Stack Developer from Indonesia currently based in Japan.

Passionate in software development, I write my thoughts and experiments into this personal blog.