{"id":4632326,"url":"https://probablyup.github.io/markdown-to-jsx","last_synced_at":"2025-09-10T23:32:54.481Z","repository":{"id":38144829,"uuid":"47486737","full_name":"quantizor/markdown-to-jsx","owner":"quantizor","description":"🏭 The most lightweight, customizable React markdown component.","archived":false,"fork":false,"pushed_at":"2024-12-18T06:07:02.000Z","size":207514,"stargazers_count":2062,"open_issues_count":141,"forks_count":179,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-01-03T08:06:13.719Z","etag":null,"topics":["gfm","jsx","markdown","react","remark"],"latest_commit_sha":null,"homepage":"https://markdown-to-jsx.quantizor.dev/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/quantizor.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"quantizor","patreon":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2015-12-06T06:42:02.000Z","updated_at":"2024-12-31T07:51:07.000Z","dependencies_parsed_at":"2023-02-17T00:00:59.554Z","dependency_job_id":"55f2bcc9-20ac-479c-9fee-af57d63b3b0e","html_url":"https://github.com/quantizor/markdown-to-jsx","commit_stats":{"total_commits":583,"total_committers":59,"mean_commits":9.88135593220339,"dds":0.4699828473413379,"last_synced_commit":"4fa87d89ad87f97b2d9e56cb969d12f9a838f3ac"},"previous_names":["quantizor/markdown-to-jsx","probablyup/markdown-to-jsx"],"tags_count":108,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quantizor%2Fmarkdown-to-jsx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quantizor%2Fmarkdown-to-jsx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quantizor%2Fmarkdown-to-jsx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quantizor%2Fmarkdown-to-jsx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/quantizor","download_url":"https://codeload.github.com/quantizor/markdown-to-jsx/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":232581235,"owners_count":18545416,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gfm","jsx","markdown","react","remark"],"created_at":"2024-02-17T08:01:09.495Z","updated_at":"2025-09-10T23:32:54.468Z","avatar_url":"https://github.com/quantizor.png","language":"TypeScript","funding_links":["https://github.com/sponsors/quantizor"],"categories":["UI components"],"sub_categories":["Markdown"],"readme":"**markdown-to-jsx**\n\nThe most lightweight, customizable React markdown component.\n\n[![npm version](https://badge.fury.io/js/markdown-to-jsx.svg)](https://badge.fury.io/js/markdown-to-jsx) [![downloads](https://badgen.net/npm/dy/markdown-to-jsx)](https://npm-stat.com/charts.html?package=markdown-to-jsx)\n\n\u003c!-- TOC --\u003e\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Parsing Options](#parsing-options)\n    - [options.forceBlock](#optionsforceblock)\n    - [options.forceInline](#optionsforceinline)\n    - [options.wrapper](#optionswrapper)\n      - [Other useful recipes](#other-useful-recipes)\n    - [options.forceWrapper](#optionsforcewrapper)\n    - [options.overrides - Void particular banned tags](#optionsoverrides---void-particular-banned-tags)\n    - [options.overrides - Override Any HTML Tag's Representation](#optionsoverrides---override-any-html-tags-representation)\n    - [options.overrides - Rendering Arbitrary React Components](#optionsoverrides---rendering-arbitrary-react-components)\n    - [options.createElement - Custom React.createElement behavior](#optionscreateelement---custom-reactcreateelement-behavior)\n    - [options.enforceAtxHeadings](#optionsenforceatxheadings)\n    - [options.renderRule](#optionsrenderrule)\n    - [options.sanitizer](#optionssanitizer)\n    - [options.slugify](#optionsslugify)\n    - [options.namedCodesToUnicode](#optionsnamedcodestounicode)\n    - [options.disableAutoLink](#optionsdisableautolink)\n    - [options.disableParsingRawHTML](#optionsdisableparsingrawhtml)\n  - [Syntax highlighting](#syntax-highlighting)\n  - [Handling shortcodes](#handling-shortcodes)\n  - [Getting the smallest possible bundle size](#getting-the-smallest-possible-bundle-size)\n  - [Usage with Preact](#usage-with-preact)\n- [Gotchas](#gotchas)\n  - [Passing props to stringified React components](#passing-props-to-stringified-react-components)\n  - [Significant indentation inside arbitrary HTML](#significant-indentation-inside-arbitrary-html)\n    - [Code blocks](#code-blocks)\n- [Using The Compiler Directly](#using-the-compiler-directly)\n- [Changelog](#changelog)\n- [Donate](#donate)\n\n\u003c!-- /TOC --\u003e\n\n---\n\n`markdown-to-jsx` offers the following additional benefits over simple markdown parsing:\n\n- Arbitrary HTML is supported and parsed into the appropriate JSX representation\n  without `dangerouslySetInnerHTML`\n\n- Any HTML tags rendered by the compiler and/or `\u003cMarkdown\u003e` component can be overridden to include additional\n  props or even a different HTML representation entirely.\n\n- GFM task list support.\n\n- Fenced code blocks with [highlight.js](https://highlightjs.org/) support; see [Syntax highlighting](#syntax-highlighting) for instructions on setting up highlight.js.\n\nAll this clocks in at around 6 kB gzipped, which is a fraction of the size of most other React markdown components.\n\nRequires React \u003e= 0.14.\n\n## Installation\n\nInstall `markdown-to-jsx` with your favorite package manager.\n\n```shell\nnpm i markdown-to-jsx\n```\n\n## Usage\n\n`markdown-to-jsx` exports a React component by default for easy JSX composition:\n\nES6-style usage\\*:\n\n```jsx\nimport Markdown from 'markdown-to-jsx'\nimport React from 'react'\nimport { render } from 'react-dom'\n\nrender(\u003cMarkdown\u003e# Hello world!\u003c/Markdown\u003e, document.body)\n\n/*\n    renders:\n\n    \u003ch1\u003eHello world!\u003c/h1\u003e\n */\n```\n\n\\* **NOTE: JSX does not natively preserve newlines in multiline text. In general, writing markdown directly in JSX is discouraged and it's a better idea to keep your content in separate .md files and require them, perhaps using webpack's [raw-loader](https://github.com/webpack-contrib/raw-loader).**\n\n### Parsing Options\n\n#### options.forceBlock\n\nBy default, the compiler will try to make an intelligent guess about the content passed and wrap it in a `\u003cdiv\u003e`, `\u003cp\u003e`, or `\u003cspan\u003e` as needed to satisfy the \"inline\"-ness of the markdown. For instance, this string would be considered \"inline\":\n\n```md\nHello. _Beautiful_ day isn't it?\n```\n\nBut this string would be considered \"block\" due to the existence of a header tag, which is a block-level HTML element:\n\n```md\n# Whaddup?\n```\n\nHowever, if you really want all input strings to be treated as \"block\" layout, simply pass `options.forceBlock = true` like this:\n\n```jsx\n;\u003cMarkdown options={{ forceBlock: true }}\u003eHello there old chap!\u003c/Markdown\u003e\n\n// or\n\ncompiler('Hello there old chap!', { forceBlock: true })\n\n// renders\n;\u003cp\u003eHello there old chap!\u003c/p\u003e\n```\n\n#### options.forceInline\n\nThe inverse is also available by passing `options.forceInline = true`:\n\n```jsx\n;\u003cMarkdown options={{ forceInline: true }}\u003e# You got it babe!\u003c/Markdown\u003e\n\n// or\n\ncompiler('# You got it babe!', { forceInline: true })\n\n// renders\n;\u003cspan\u003e# You got it babe!\u003c/span\u003e\n```\n\n#### options.wrapper\n\nWhen there are multiple children to be rendered, the compiler will wrap the output in a `div` by default. You can override this default by setting the `wrapper` option to either a string (React Element) or a component.\n\n```jsx\nconst str = '# Heck Yes\\n\\nThis is great!'\n\n\u003cMarkdown options={{ wrapper: 'article' }}\u003e\n  {str}\n\u003c/Markdown\u003e;\n\n// or\n\ncompiler(str, { wrapper: 'article' });\n\n// renders\n\n\u003carticle\u003e\n  \u003ch1\u003eHeck Yes\u003c/h1\u003e\n  \u003cp\u003eThis is great!\u003c/p\u003e\n\u003c/article\u003e\n```\n\n##### Other useful recipes\n\nTo get an array of children back without a wrapper, set `wrapper` to `null`. This is particularly useful when using `compiler(…)` directly.\n\n```jsx\ncompiler('One\\n\\nTwo\\n\\nThree', { wrapper: null })\n\n// returns\n;[\u003cp\u003eOne\u003c/p\u003e, \u003cp\u003eTwo\u003c/p\u003e, \u003cp\u003eThree\u003c/p\u003e]\n```\n\nTo render children at the same DOM level as `\u003cMarkdown\u003e` with no HTML wrapper, set `wrapper` to `React.Fragment`. This will still wrap your children in a React node for the purposes of rendering, but the wrapper element won't show up in the DOM.\n\n#### options.forceWrapper\n\nBy default, the compiler does not wrap the rendered contents if there is only a single child. You can change this by setting `forceWrapper` to `true`. If the child is inline, it will not necessarily be wrapped in a `span`.\n\n```jsx\n// Using `forceWrapper` with a single, inline child…\n\u003cMarkdown options={{ wrapper: 'aside', forceWrapper: true }}\u003e\n  Mumble, mumble…\n\u003c/Markdown\u003e\n\n// renders\n\n\u003caside\u003eMumble, mumble…\u003c/aside\u003e\n```\n\n#### options.overrides - Void particular banned tags\n\nPass the `options.overrides` prop to the compiler or `\u003cMarkdown\u003e` component with an implementation that return `null` for tags you wish to exclude from the rendered output. It is recommended to void `script`, `iframe`, `object`, and `style` tags to avoid XSS attacks when working with user-generated content. For example, to void the `iframe` tag:\n\n```tsx\nimport Markdown from 'markdown-to-jsx'\nimport React from 'react'\nimport { render } from 'react-dom'\n\nrender(\n  \u003cMarkdown options={{ overrides: { iframe: () =\u003e null } }}\u003e\n    \u003ciframe src=\"https://potentially-malicious-web-page.com/\"\u003e\u003c/iframe\u003e\n  \u003c/Markdown\u003e,\n  document.body\n)\n\n// renders: \"\"\n```\n\nThe library does not void any tags by default to avoid surprising behavior for personal use cases.\n\n#### options.overrides - Override Any HTML Tag's Representation\n\nPass the `options.overrides` prop to the compiler or `\u003cMarkdown\u003e` component to seamlessly revise the rendered representation of any HTML tag. You can choose to change the component itself, add/change props, or both.\n\n```jsx\nimport Markdown from 'markdown-to-jsx'\nimport React from 'react'\nimport { render } from 'react-dom'\n\n// surprise, it's a div instead!\nconst MyParagraph = ({ children, ...props }) =\u003e \u003cdiv {...props}\u003e{children}\u003c/div\u003e\n\nrender(\n  \u003cMarkdown\n    options={{\n      overrides: {\n        h1: {\n          component: MyParagraph,\n          props: {\n            className: 'foo',\n          },\n        },\n      },\n    }}\n  \u003e\n    # Hello world!\n  \u003c/Markdown\u003e,\n  document.body\n)\n\n/*\n    renders:\n\n    \u003cdiv class=\"foo\"\u003e\n        Hello World\n    \u003c/div\u003e\n */\n```\n\nIf you only wish to provide a component override, a simplified syntax is available:\n\n```js\n{\n    overrides: {\n        h1: MyParagraph,\n    },\n}\n```\n\nDepending on the type of element, there are some props that must be preserved to ensure the markdown is converted as intended. They are:\n\n- `a`: `title`, `href`\n- `img`: `title`, `alt`, `src`\n- `input[type=\"checkbox\"]`: `checked`, `readonly` (specifically, the one rendered by a GFM task list)\n- `ol`: `start`\n- `td`: `style`\n- `th`: `style`\n\nAny conflicts between passed `props` and the specific properties above will be resolved in favor of `markdown-to-jsx`'s code.\n\nSome element mappings are a bit different from other libraries, in particular:\n\n- `span`: Used for inline text.\n- `code`: Used for inline code.\n- `pre \u003e code`: Code blocks are a `code` element with a `pre` as its direct ancestor.\n\n#### options.overrides - Rendering Arbitrary React Components\n\nOne of the most interesting use cases enabled by the HTML syntax processing in `markdown-to-jsx` is the ability to use any kind of element, even ones that aren't real HTML tags like React component classes.\n\nBy adding an override for the components you plan to use in markdown documents, it's possible to dynamically render almost anything. One possible scenario could be writing documentation:\n\n```jsx\nimport Markdown from 'markdown-to-jsx'\nimport React from 'react'\nimport { render } from 'react-dom'\n\nimport DatePicker from './date-picker'\n\nconst md = `\n# DatePicker\n\nThe DatePicker works by supplying a date to bias towards,\nas well as a default timezone.\n\n\u003cDatePicker biasTowardDateTime=\"2017-12-05T07:39:36.091Z\" timezone=\"UTC+5\" /\u003e\n`\n\nrender(\n  \u003cMarkdown\n    children={md}\n    options={{\n      overrides: {\n        DatePicker: {\n          component: DatePicker,\n        },\n      },\n    }}\n  /\u003e,\n  document.body\n)\n```\n\n`markdown-to-jsx` also handles JSX interpolation syntax, but in a minimal way to not introduce a potential attack vector. Interpolations are sent to the component as their raw string, which the consumer can then `eval()` or process as desired to their security needs.\n\nIn the following case, `DatePicker` could simply run `parseInt()` on the passed `startTime` for example:\n\n```jsx\nimport Markdown from 'markdown-to-jsx'\nimport React from 'react'\nimport { render } from 'react-dom'\n\nimport DatePicker from './date-picker'\n\nconst md = `\n# DatePicker\n\nThe DatePicker works by supplying a date to bias towards,\nas well as a default timezone.\n\n\u003cDatePicker\n  biasTowardDateTime=\"2017-12-05T07:39:36.091Z\"\n  timezone=\"UTC+5\"\n  startTime={1514579720511}\n/\u003e\n`\n\nrender(\n  \u003cMarkdown\n    children={md}\n    options={{\n      overrides: {\n        DatePicker: {\n          component: DatePicker,\n        },\n      },\n    }}\n  /\u003e,\n  document.body\n)\n```\n\nAnother possibility is to use something like [recompose's `withProps()` HOC](https://github.com/acdlite/recompose/blob/main/docs/API.md#withprops) to create various pregenerated scenarios and then reference them by name in the markdown:\n\n```jsx\nimport Markdown from 'markdown-to-jsx'\nimport React from 'react'\nimport { render } from 'react-dom'\nimport withProps from 'recompose/withProps'\n\nimport DatePicker from './date-picker'\n\nconst DecemberDatePicker = withProps({\n  range: {\n    start: new Date('2017-12-01'),\n    end: new Date('2017-12-31'),\n  },\n  timezone: 'UTC+5',\n})(DatePicker)\n\nconst md = `\n# DatePicker\n\nThe DatePicker works by supplying a date to bias towards,\nas well as a default timezone.\n\n\u003cDatePicker\n  biasTowardDateTime=\"2017-12-05T07:39:36.091Z\"\n  timezone=\"UTC+5\"\n  startTime={1514579720511}\n/\u003e\n\nHere's an example of a DatePicker pre-set to only the month of December:\n\n\u003cDecemberDatePicker /\u003e\n`\n\nrender(\n  \u003cMarkdown\n    children={md}\n    options={{\n      overrides: {\n        DatePicker,\n        DecemberDatePicker,\n      },\n    }}\n  /\u003e,\n  document.body\n)\n```\n\n#### options.createElement - Custom React.createElement behavior\n\nSometimes, you might want to override the `React.createElement` default behavior to hook into the rendering process before the JSX gets rendered. This might be useful to add extra children or modify some props based on runtime conditions. The function mirrors the `React.createElement` function, so the params are [`type, [props], [...children]`](https://reactjs.org/docs/react-api.html#createelement):\n\n```javascript\nimport Markdown from 'markdown-to-jsx'\nimport React from 'react'\nimport { render } from 'react-dom'\n\nconst md = `\n# Hello world\n`\n\nrender(\n  \u003cMarkdown\n    children={md}\n    options={{\n      createElement(type, props, children) {\n        return (\n          \u003cdiv className=\"parent\"\u003e\n            {React.createElement(type, props, children)}\n          \u003c/div\u003e\n        )\n      },\n    }}\n  /\u003e,\n  document.body\n)\n```\n\n#### options.enforceAtxHeadings\n\nForces the compiler to have space between hash sign `#` and the header text which is explicitly stated in the most of the [markdown specs](https://github.github.com/gfm/#atx-heading).\n\n\u003e The opening sequence of `#` characters must be followed by a space or by the end of line.\n\n#### options.renderRule\n\nSupply your own rendering function that can selectively override how _rules_ are rendered (note, this is different than _`options.overrides`_ which operates at the HTML tag level and is more general). You can use this functionality to do pretty much anything with an established AST node; here's an example of selectively overriding the \"codeBlock\" rule to process LaTeX syntax using the `@matejmazur/react-katex` library:\n\n````tsx\nimport Markdown, { RuleType } from 'markdown-to-jsx'\nimport TeX from '@matejmazur/react-katex'\n\nconst exampleContent =\n  'Some important formula:\\n\\n```latex\\nmathbb{N} = { a in mathbb{Z} : a \u003e 0 }\\n```\\n'\n\nfunction App() {\n  return (\n    \u003cMarkdown\n      children={exampleContent}\n      options={{\n        renderRule(next, node, renderChildren, state) {\n          if (node.type === RuleType.codeBlock \u0026\u0026 node.lang === 'latex') {\n            return (\n              \u003cTeX as=\"div\" key={state.key}\u003e{String.raw`${node.text}`}\u003c/TeX\u003e\n            )\n          }\n\n          return next()\n        },\n      }}\n    /\u003e\n  )\n}\n````\n\n#### options.sanitizer\n\nBy default a lightweight URL sanitizer function is provided to avoid common attack vectors that might be placed into the `href` of an anchor tag, for example. The sanitizer receives the input, the HTML tag being targeted, and the attribute name. The original function is available as a library export called `sanitizer`.\n\nThis can be overridden and replaced with a custom sanitizer if desired via `options.sanitizer`:\n\n```jsx\n// sanitizer in this situation would receive:\n// ('javascript:alert(\"foo\")', 'a', 'href')\n\n;\u003cMarkdown options={{ sanitizer: (value, tag, attribute) =\u003e value }}\u003e\n  {`[foo](javascript:alert(\"foo\"))`}\n\u003c/Markdown\u003e\n\n// or\n\ncompiler('[foo](javascript:alert(\"foo\"))', {\n  sanitizer: (value, tag, attribute) =\u003e value,\n})\n```\n\n#### options.slugify\n\nBy default, a [lightweight deburring function](https://github.com/probablyup/markdown-to-jsx/blob/bc2f57412332dc670f066320c0f38d0252e0f057/index.js#L261-L275) is used to generate an HTML id from headings. You can override this by passing a function to `options.slugify`. This is helpful when you are using non-alphanumeric characters (e.g. Chinese or Japanese characters) in headings. For example:\n\n```jsx\n\u003cMarkdown options={{ slugify: str =\u003e str }}\u003e# 中文\u003c/Markdown\u003e\n\n// or\n\ncompiler('# 中文', { slugify: str =\u003e str })\n\n// renders:\n\u003ch1 id=\"中文\"\u003e中文\u003c/h1\u003e\n```\n\nThe original function is available as a library export called `slugify`.\n\n#### options.namedCodesToUnicode\n\nBy default only a couple of named html codes are converted to unicode characters:\n\n- `\u0026` (`\u0026amp;`)\n- `'` (`\u0026apos;`)\n- `\u003e` (`\u0026gt;`)\n- `\u003c` (`\u0026lt;`)\n- ` ` (`\u0026nbsp;`)\n- `\"` (`\u0026quot;`)\n\nSome projects require to extend this map of named codes and unicode characters. To customize this list with additional html codes pass the option namedCodesToUnicode as object with the code names needed as in the example below:\n\n```jsx\n\u003cMarkdown options={{ namedCodesToUnicode: {\n    le: '\\u2264',\n    ge: '\\u2265',\n    '#39': '\\u0027',\n} }}\u003eThis text is \u0026le; than this text.\u003c/Markdown\u003e;\n\n// or\n\ncompiler('This text is \u0026le; than this text.', namedCodesToUnicode: {\n    le: '\\u2264',\n    ge: '\\u2265',\n    '#39': '\\u0027',\n});\n\n// renders:\n\n\u003cp\u003eThis text is ≤ than this text.\u003c/p\u003e\n```\n\n#### options.disableAutoLink\n\nBy default, bare URLs in the markdown document will be converted into an anchor tag. This behavior can be disabled if desired.\n\n```jsx\n\u003cMarkdown options={{ disableAutoLink: true }}\u003e\n  The URL https://quantizor.dev will not be rendered as an anchor tag.\n\u003c/Markdown\u003e\n\n// or\n\ncompiler(\n  'The URL https://quantizor.dev will not be rendered as an anchor tag.',\n  { disableAutoLink: true }\n)\n\n// renders:\n\n\u003cspan\u003e\n  The URL https://quantizor.dev will not be rendered as an anchor tag.\n\u003c/span\u003e\n```\n\n#### options.disableParsingRawHTML\n\nBy default, raw HTML is parsed to JSX. This behavior can be disabled if desired.\n\n```jsx\n\u003cMarkdown options={{ disableParsingRawHTML: true }}\u003e\n    This text has \u003cspan\u003ehtml\u003c/span\u003e in it but it won't be rendered\n\u003c/Markdown\u003e;\n\n// or\n\ncompiler('This text has \u003cspan\u003ehtml\u003c/span\u003e in it but it won't be rendered', { disableParsingRawHTML: true });\n\n// renders:\n\n\u003cspan\u003eThis text has \u0026lt;span\u0026gt;html\u0026lt;/span\u0026gt; in it but it won't be rendered\u003c/span\u003e\n```\n\n### Syntax highlighting\n\nWhen using [fenced code blocks](https://www.markdownguide.org/extended-syntax/#syntax-highlighting) with language annotation, that language will be added to the `\u003ccode\u003e` element as `class=\"lang-${language}\"`. For best results, you can use `options.overrides` to provide an appropriate syntax highlighting integration like this one using `highlight.js`:\n\n````jsx\nimport { Markdown, RuleType } from 'markdown-to-jsx'\n\nconst mdContainingFencedCodeBlock = '```js\\nconsole.log(\"Hello world!\");\\n```\\n'\n\nfunction App() {\n  return (\n    \u003cMarkdown\n      children={mdContainingFencedCodeBlock}\n      options={{\n        overrides: {\n          code: SyntaxHighlightedCode,\n        },\n      }}\n    /\u003e\n  )\n}\n\n/**\n * Add the following tags to your page \u003chead\u003e to automatically load hljs and styles:\n\n  \u003clink\n    rel=\"stylesheet\"\n    href=\"https://unpkg.com/@highlightjs/cdn-assets@11.9.0/styles/nord.min.css\"\n  /\u003e\n\n  * NOTE: for best performance, load individual languages you need instead of all\n          of them. See their docs for more info: https://highlightjs.org/\n\n  \u003cscript\n    crossorigin\n    src=\"https://unpkg.com/@highlightjs/cdn-assets@11.9.0/highlight.min.js\"\n  \u003e\u003c/script\u003e\n */\n\nfunction SyntaxHighlightedCode(props) {\n  const ref = (React.useRef \u003c HTMLElement) | (null \u003e null)\n\n  React.useEffect(() =\u003e {\n    if (ref.current \u0026\u0026 props.className?.includes('lang-') \u0026\u0026 window.hljs) {\n      window.hljs.highlightElement(ref.current)\n\n      // hljs won't reprocess the element unless this attribute is removed\n      ref.current.removeAttribute('data-highlighted')\n    }\n  }, [props.className, props.children])\n\n  return \u003ccode {...props} ref={ref} /\u003e\n}\n````\n\n### Handling shortcodes\n\nFor Slack-style messaging with arbitrary shortcodes like `:smile:`, you can use `options.renderRule` to hook into the plain text rendering and adjust things to your liking, for example:\n\n```tsx\nimport Markdown, { RuleType } from 'markdown-to-jsx'\n\nconst shortcodeMap = {\n  smile: '🙂',\n}\n\nconst detector = /(:[^:]+:)/g\n\nconst replaceEmoji = (text: string): React.ReactNode =\u003e {\n  return text.split(detector).map((part, index) =\u003e {\n    if (part.startsWith(':') \u0026\u0026 part.endsWith(':')) {\n      const shortcode = part.slice(1, -1)\n\n      return \u003cspan key={index}\u003e{shortcodeMap[shortcode] || part}\u003c/span\u003e\n    }\n\n    return part\n  })\n}\n\nfunction Example() {\n  return (\n    \u003cMarkdown\n      options={{\n        renderRule(next, node) {\n          if (node.type === RuleType.text \u0026\u0026 detector.test(node.text)) {\n            return replaceEmoji(node.text)\n          }\n\n          return next()\n        },\n      }}\n    \u003e\n      {`On a beautiful summer day, all I want to do is :smile:.`}\n    \u003c/Markdown\u003e\n  )\n}\n\n// renders\n// \u003cspan\u003eOn a beautiful summer day, all I want to do is \u003cspan\u003e🙂\u003c/span\u003e.\u003c/span\u003e\n```\n\nWhen you use `options.renderRule`, any React-renderable JSX may be returned including images and GIFs. Ensure you benchmark your solution as the `text` rule is one of the hottest paths in the system!\n\n### Getting the smallest possible bundle size\n\nMany development conveniences are placed behind `process.env.NODE_ENV !== \"production\"` conditionals. When bundling your app, it's a good idea to replace these code snippets such that a minifier (like uglify) can sweep them away and leave a smaller overall bundle.\n\nHere are instructions for some of the popular bundlers:\n\n- [webpack](https://webpack.js.org/guides/production/#specify-the-environment)\n- [browserify plugin](https://github.com/hughsk/envify)\n- [parcel](https://parceljs.org/production.html)\n- [fuse-box](http://fuse-box.org/plugins/replace-plugin#notes)\n\n### Usage with Preact\n\nEverything will work just fine! Simply [Alias `react` to `preact/compat`](https://preactjs.com/guide/v10/switching-to-preact#setting-up-compat) like you probably already are doing.\n\n## Gotchas\n\n### Passing props to stringified React components\n\nUsing the [`options.overrides`](#optionsoverrides---rendering-arbitrary-react-components) functionality to render React components, props are passed into the component in stringifed form. It is up to you to parse the string to make use of the data.\n\n```tsx\nconst Table: React.FC\u003c\n  JSX.IntrinsicElements['table'] \u0026 {\n    columns: string\n    dataSource: string\n  }\n\u003e = ({ columns, dataSource, ...props }) =\u003e {\n  const parsedColumns = JSON.parse(columns)\n  const parsedData = JSON.parse(dataSource)\n\n  return (\n    \u003cdiv {...props}\u003e\n      \u003ch1\u003eColumns\u003c/h1\u003e\n      {parsedColumns.map(column =\u003e (\n        \u003cspan key={column.key}\u003e{column.title}\u003c/span\u003e\n      ))}\n\n      \u003ch2\u003eData\u003c/h2\u003e\n      {parsedData.map(datum =\u003e (\n        \u003cspan key={datum.key}\u003e{datum.Month}\u003c/span\u003e\n      ))}\n    \u003c/div\u003e\n  )\n}\n\n/**\n * Example HTML in markdown:\n *\n * \u003cTable\n *    columns={[{ title: 'Month', dataIndex: 'Month', key: 'Month' }]}\n *    dataSource={[\n *      {\n *        Month: '2024-09-01',\n *        'Forecasted Revenue': '$3,137,678.85',\n *        'Forecasted Expenses': '$2,036,660.28',\n *        key: 0,\n *      },\n *    ]}\n *  /\u003e\n */\n```\n\n### Significant indentation inside arbitrary HTML\n\nPeople usually write HTML like this:\n\n```html\n\u003cdiv\u003eHey, how are you?\u003c/div\u003e\n```\n\nNote the leading spaces before the inner content. This sort of thing unfortunately clashes with existing markdown syntaxes since 4 spaces === a code block and other similar collisions.\n\nTo get around this, `markdown-to-jsx` left-trims approximately as much whitespace as the first line inside the HTML block. So for example:\n\n```html\n\u003cdiv\u003e# Hello How are you?\u003c/div\u003e\n```\n\nThe two leading spaces in front of \"# Hello\" would be left-trimmed from all lines inside the HTML block. In the event that there are varying amounts of indentation, only the amount of the first line is trimmed.\n\n\u003e NOTE! These syntaxes work just fine when you aren't writing arbitrary HTML wrappers inside your markdown. This is very much an edge case of an edge case. 🙃\n\n#### Code blocks\n\n⛔️\n\n```md\n\u003cdiv\u003e\n    var some = code();\n\u003c/div\u003e\n```\n\n✅\n\n````md\n\u003cdiv\u003e\n```js\nvar some = code();\n``\\`\n\u003c/div\u003e\n````\n\n## Using The Compiler Directly\n\nIf desired, the compiler function is a \"named\" export on the `markdown-to-jsx` module:\n\n```jsx\nimport { compiler } from 'markdown-to-jsx'\nimport React from 'react'\nimport { render } from 'react-dom'\n\nrender(compiler('# Hello world!'), document.body)\n\n/*\n    renders:\n\n    \u003ch1\u003eHello world!\u003c/h1\u003e\n */\n```\n\nIt accepts the following arguments:\n\n```js\ncompiler(markdown: string, options: object?)\n```\n\n## Changelog\n\nSee [Github Releases](https://github.com/probablyup/markdown-to-jsx/releases).\n\n## Donate\n\nLike this library? It's developed entirely on a volunteer basis; chip in a few bucks if you can via the Sponsor link!\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/probablyup.github.io%2Fmarkdown-to-jsx","html_url":"https://awesome.ecosyste.ms/projects/probablyup.github.io%2Fmarkdown-to-jsx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/probablyup.github.io%2Fmarkdown-to-jsx/lists"}