React Showdown: Markdown with Embedded Components
react-showdown is a React component library designed for rendering Markdown content within React applications. It leverages the underlying Showdown.js parser, providing a robust solution for Markdown-to-HTML conversion. A key differentiator of this library is its unique capability to embed actual React components directly within Markdown text, which are then rendered seamlessly as part of the React component tree. This feature significantly enhances interactivity and modularity, moving beyond static HTML. The library, currently at stable version 2.3.1, also boasts full TypeScript support and offers extensive configuration options by supporting all Showdown extensions and flavors. While a specific release cadence isn't explicitly stated, the version history (2.0, 2.1, 2.3.1) suggests a pattern of incremental updates focused on new features and bug fixes.
Common errors
-
Error: Objects are not valid as a React child (found: object with keys {CustomComponent}). If you meant to render a collection of children, use an array instead.cause Incorrectly passing the `components` prop. The `components` prop expects an object where keys are the component names used in markdown and values are the React component functions themselves, not an array or a deeply nested object.fixEnsure the `components` prop is an object with direct references to your React components: `<MarkdownView components={{ YourComponent }} />`. -
TypeError: Cannot read properties of undefined (reading 'markdown') (or similar property access errors related to props)
cause The required `markdown` prop was not provided or was `undefined` when rendering the `MarkdownView` component.fixAlways pass a string value, even an empty one, to the `markdown` prop: `<MarkdownView markdown={myMarkdownString} />`. -
Markdown content appears truncated or parts are missing, especially after custom HTML-like tags.
cause This typically occurs in versions prior to 2.1.0, or if `recognizeSelfClosing` is explicitly set to `false`, preventing Showdown from correctly parsing content after self-closing elements.fixUpgrade `react-showdown` to version 2.1.0 or newer. If upgrading isn't an option, or if the issue persists, ensure `options={{ recognizeSelfClosing: true }}` is passed to `MarkdownView`.
Warnings
- gotcha In `react-showdown` v2.1.0, the default value for the `showdown` configuration option `recognizeSelfClosing` was changed to `true`. This fixed an issue where content might be missing after a self-closing component. If you were explicitly setting `recognizeSelfClosing: false` or relying on the previous (buggy) default behavior, your rendered output might change.
- breaking This library requires React version 16 or newer as a peer dependency. Using it with older React versions (e.g., React 15) will result in installation errors or runtime failures due to incompatible React APIs.
Install
-
npm install react-showdown -
yarn add react-showdown -
pnpm add react-showdown
Imports
- MarkdownView
import { MarkdownView } from 'react-showdown';import MarkdownView from 'react-showdown';
- ConverterOptions
import { ConverterOptions } from 'react-showdown';import type { ConverterOptions } from 'react-showdown'; - Flavor
import { Flavor } from 'react-showdown';import type { Flavor } from 'react-showdown';
Quickstart
import React from 'react';
import MarkdownView from 'react-showdown';
function CustomComponent({ name }: { name: string }) {
return <span style={{ color: 'blue', fontWeight: 'bold' }}>Hello {name}!</span>;
}
export default function App() {
const basicMarkdown = `
# Welcome to React Showdown :wave:
This is a simple markdown example with a table and emojis.
| Header 1 | Header 2 |
|----------|----------|
| Cell A1 | Cell B1 |
| Cell A2 | Cell B2 |
`;
const markdownWithComponent = `
# Embedding React Components
Here's a custom component: <CustomComponent name="World" />
You can pass props and define complex logic within them.
`;
return (
<div>
<h2>Basic Markdown Render:</h2>
<MarkdownView
markdown={basicMarkdown}
options={{ tables: true, emoji: true, simpleLineBreaks: true }}
className="markdown-output"
/>
<h2>Markdown with Custom Component:</h2>
<MarkdownView
markdown={markdownWithComponent}
components={{ CustomComponent }}
className="markdown-output"
/>
</div>
);
};