DEV Community

Cover image for Enhance Your Markdown with Custom React Components using react-markdown
Adam Kopański
Adam Kopański

Posted on

Enhance Your Markdown with Custom React Components using react-markdown

Intro

Markdown is great for static content, but what if you want to inject dynamic React components into your Markdown files? With react-markdown, you can customize how Markdown elements are rendered—including links, images, code blocks, and even custom tags.

In this post, I’ll show you how to:

  • Use standard Markdown link syntax
  • Map specific links or syntax to custom React components
  • Enhance your Markdown content with live React behavior

Why This Matters
This is especially useful for:

  • Documentation sites
  • Developer blogs
  • Interactive tutorials or component previews
  • Any site where you want a mix of Markdown and dynamic behavior

1. How to Use Markdown with react-markdown.

Here's how you can create a basic React component that renders Markdown using the react-markdown library:

import ReactMarkdown from 'react-markdown';

const markdown = `
   ## Hello World

   Check out this [Google](https://google.com) page.
`;

function MarkdownRenderer() {
  return <ReactMarkdown children={markdown} />;
}

Enter fullscreen mode Exit fullscreen mode

2. How to Extend Markdown Syntax with React Components

To achieve our goal, we’ll follow a few simple steps:

  1. Establish a “vocabulary” for your custom components.
  2. Create a react-markdown-based component (as in the previous step).
  3. Map custom Markdown links (your vocabulary) to React components via the components prop of react-markdown.

For this example, I’ll use one custom element called custom-button, but you can define as many as you like—naming conventions are fully up to you.

You can add react-markdown to your project by running:

npm install react-markdown

Enter fullscreen mode Exit fullscreen mode

Component implementation:

import React from 'react';
import ReactMarkdown from 'react-markdown';

const components = {
  a: ({ href, children }) => {
    if (href === 'customButton') {
      return <CustomButton>{children}</CustomButton>;
    }
    return <a href={href}>{children}</a>;
  },
};

const CustomButton = ({ children }) => {
  return <button className="btn btn-primary">{children}</button>;
}

const markdown = `
## Try This!

Click [here](custom-button) to activate the button!
`;

const MarkdownRenderer = () => (
  <ReactMarkdown components={components}>{markdown}</ReactMarkdown>;
)
Enter fullscreen mode Exit fullscreen mode

In Markdown, a link ([here](custom-button)) consists of two parts: the link text (what’s shown to the user) and the URL/href. Knowing this, we can use the components mapping feature provided by react-markdown to replace custom link values with corresponding React components.

If a link in your Markdown doesn’t match any custom mapping, a standard <a> tag will be rendered instead.

3. Scaling the Approach

You can scale this to support:

  • Multiple custom components
  • Automatic mapping using a component registry
  • Support for parameters in your custom link syntax (e.g. http://some-name?label=some-label)

Here's an example registry-based approach:

const componentRegistry = {
  CustomButton: (props) => <button className="btn">{props.children}</button>,
  AlertBox: (props) => <div className="alert">{props.children}</div>,
};

const CustomLinkRenderer = ({ href, children }) => {
  if (href) {
    const Component = componentRegistry[href];
    return Component ? <Component>{children}</Component> : null;
  }

  return <a href={href}>{children}</a>;
};

const components = {
  a: CustomLinkRenderer,
};
Enter fullscreen mode Exit fullscreen mode

4. Caveats and Gotchas

  • Always validate URLs or inputs if user-generated Markdown is allowed.
  • react-markdown sanitizes input by default. Keep this in my mind if you're trying to allow raw HTML.
  • You can extend beyond just <a>: override code, img, blockquote, etc.

Conclusion

By using the components prop from react-markdown, you gain full control over how Markdown is rendered—allowing you to seamlessly combine Markdown’s simplicity with the power of React components.

Have questions? Let me know in the comments 👇

Top comments (0)