{"id":15641459,"url":"https://github.com/ticky/markdown-component-loader","last_synced_at":"2025-04-05T03:09:53.779Z","repository":{"id":39559411,"uuid":"71106545","full_name":"ticky/markdown-component-loader","owner":"ticky","description":"📑 Turn Markdown into dynamic, stateless React components","archived":false,"fork":false,"pushed_at":"2025-03-28T22:54:23.000Z","size":19435,"stargazers_count":71,"open_issues_count":55,"forks_count":8,"subscribers_count":2,"default_branch":"develop","last_synced_at":"2025-03-28T23:29:26.308Z","etag":null,"topics":["loader","markdown","react-components"],"latest_commit_sha":null,"homepage":"https://ticky.github.io/markdown-component-loader/","language":"JavaScript","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/ticky.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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}},"created_at":"2016-10-17T06:25:48.000Z","updated_at":"2024-06-14T03:18:49.000Z","dependencies_parsed_at":"2023-02-04T06:45:44.371Z","dependency_job_id":"628c998f-fbfa-4f73-abdc-59a84f2f9ea4","html_url":"https://github.com/ticky/markdown-component-loader","commit_stats":{"total_commits":354,"total_committers":7,"mean_commits":50.57142857142857,"dds":0.4971751412429378,"last_synced_commit":"d2f94e9e112741adef23b8a1869f928f5694adcf"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ticky%2Fmarkdown-component-loader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ticky%2Fmarkdown-component-loader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ticky%2Fmarkdown-component-loader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ticky%2Fmarkdown-component-loader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ticky","download_url":"https://codeload.github.com/ticky/markdown-component-loader/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247280272,"owners_count":20912967,"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":["loader","markdown","react-components"],"created_at":"2024-10-03T11:42:39.383Z","updated_at":"2025-04-05T03:09:53.761Z","avatar_url":"https://github.com/ticky.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Markdown Component Loader\n[![npm](https://img.shields.io/npm/v/markdown-component-loader.svg?maxAge=2592000)](https://www.npmjs.com/package/markdown-component-loader) ![markdown-component-loader](https://img.shields.io/npm/l/markdown-component-loader.svg?maxAge=2592000) [![Build Status](https://travis-ci.org/ticky/markdown-component-loader.svg?branch=master)](https://travis-ci.org/ticky/markdown-component-loader) [![codecov](https://codecov.io/gh/ticky/markdown-component-loader/branch/master/graph/badge.svg)](https://codecov.io/gh/ticky/markdown-component-loader)\n\nTurn Markdown into dynamic, stateless React components\n\n- Integrate documentation and other prose with user info and context\n- Show your real UI components alongside documentation\n- Add other dynamic components inside documentation\n\n## Usage\n\n### Installation\n\n```shell\nyarn add markdown-component-loader\n```\n\n\\~_or_\\~\n\n```shell\nnpm install --save markdown-component-loader\n```\n\nYou'll need both Babel and Webpack in order to use it.\n\n### Webpack Configuration\n\nYou then need to configure Webpack to use the loader, in your `webpack.config.js`;\n\n```javascript\nmodule.exports = {\n  module: {\n    loaders: [\n      {\n        test: /\\.mdx$/i,\n        loader: 'babel-loader!markdown-component-loader'\n      },\n      {...more}\n    ]\n  },\n  {...more}\n};\n```\n\n### Usage and Syntax\n\n`mdx` allows you interleave both React props and React components within your prose and code snippets! `mdx` files may optionally start with yaml-formatted front-matter.\n\nFront-matter accepts `imports`, which will be included in the React component's definition. Other front-matter keys are added as static properties of the resultant Markdown component.\n\nHere's an example of an `mdx` file;\n```markdown\n---\nimports:\n  '{ name, version }': ./package.json\ndisplayName: MarkdownComponentLoaderReadme\n---\n\nThis is a _Markdown Component_ file. Here you can include JSX-style assignment expressions; this component was generated using version {{ version }} of {{ name }}!\n\nProps passed to this component are available as `props`, so you can embed those too! Hello there, {{ props.who || 'world' }}!\n\nAnother cool thing you can do is use JSX **directly** - here’s an SVG element, used inline: \u003csvg style={{ display: 'inline', height: '1em' }} viewBox=\"0 0 304 290\"\u003e\u003cpath fill=\"none\" stroke=\"currentColor\" strokeWidth=\"16\" d=\"M2,111 h300 l-242.7,176.3 92.7,-285.3 92.7,285.3 z\" /\u003e\u003c/svg\u003e.\n\n```\n\n_**Note**: destructuring imports must be quoted, but others need not be._\n\nThe above `mdx` file will produce the following module within Webpack;\n\n```javascript\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport { name, version } from './package.json';\n\nMarkdownComponent.propTypes = {\n  className: PropTypes.string,\n  style: PropTypes.object\n};\n\nMarkdownComponent['displayName'] = 'MarkdownComponentLoaderReadme';\n\nfunction MarkdownComponent(props) {\n  const {className, style} = props;\n\n  return (\n    \u003cdiv className={className} style={style}\u003e\n      \u003cp\u003eThis is a \u003cem\u003eMarkdown Component\u003c/em\u003e file. Here you can include JSX-style assignment expressions; this component was generated using version { version } of { name }!\u003c/p\u003e\n      \u003cp\u003eProps passed to this component are available as \u003ccode\u003eprops\u003c/code\u003e, so you can embed those too! Hello there, { props.who || 'world' }!\u003c/p\u003e\n      \u003cp\u003eAnother cool thing you can do is use JSX \u003cstrong\u003edirectly\u003c/strong\u003e - here’s an SVG element, used inline: \u003csvg style={{ display: 'inline', height: '1em' }} viewBox=\"0 0 304 290\"\u003e\u003cpath fill=\"none\" stroke=\"currentColor\" strokeWidth=\"16\" d=\"M2,111 h300 l-242.7,176.3 92.7,-285.3 92.7,285.3 z\" /\u003e\u003c/svg\u003e.\u003c/p\u003e\n    \u003c/div\u003e\n  );\n};\n\nexport default MarkdownComponent;\n\n```\n\nYou can then include it anywhere you like in your own React code;\n\n```javascript\nimport ReactDOM from 'react-dom';\n\nimport Readme from './readme.mdx';\n\nReactDOM.render(\n  \u003cReadme who=\"you\" /\u003e,\n  document.getElementById('main')\n);\n```\n\n### Extra Configuration\n\nMarkdown Component Loader accepts configuration of options via the Webpack configuration file.\n\n```javascript\nmodule.exports = {\n  module: {\n    rules: [\n      {...more},\n      {\n        test: /\\.mdx$/i,\n        use: [\n          'babel-loader',\n          {\n            loader: 'markdown-component-loader',\n            options: {...options}\n          }\n        ]\n      }\n    ]\n  },\n  {...more}\n};\n```\n\n#### Available Options\n\n* `passElementProps`: Controls whether props can be passed from the parent to the generated elements. Defaults to `false`.\n* `implicitlyImportReact`: Whether to include React and PropTypes in the imports automatically. If set to `false`, you need to either supply React and PropTypes or import them explicitly. Defaults to `true`.\n* `markdownItPlugins`: An array of [MarkdownIt plugins](https://www.npmjs.org/browse/keyword/markdown-it-plugin) (and optionally their additional arguments) to use within the markdown renderer. These can be specified either as instances, or as paths as returned by `require.resolve`.\n\n##### MarkdownIt Plugins\n\nIf you supply an array of [MarkdownIt plugins](https://www.npmjs.org/browse/keyword/markdown-it-plugin) as `markdownItPlugins`, Markdown Component Loader will chain them into the internal MarkdownIt renderer.\n\n```javascript\n{\n  loader: 'markdown-component-loader',\n  options: {\n    markdownItPlugins: [\n      require('markdown-it-anchor'),\n      [require('markdown-it-table-of-contents'), { containerClass: 'my-container-class' }]\n    ]\n  },\n  {...more}\n}\n```\n\nThe configuration above will supply both [`markdown-it-anchor`](https://www.npmjs.com/package/markdown-it-anchor) and [`markdown-it-table-of-contents`](https://www.npmjs.com/package/markdown-it-table-of-contents) to MarkdownIt's `use` method. `markdown-it-table-of-contents` is supplied within an array, and the entire array is passed as the arguments to `use`, allowing specifying plugin configurations.\n\n###### Legacy Webpack compatibility\n\nFor compatibility with Webpack 1.x, where plugin configuration must be JSON compatible, plugins can be passed as path strings rather than the plugin object itself.\n\nThe equivalent of the example above in Webpack 1.x would be as follows.\n\n```javascript\nmodule.exports = {\n  markdownComponentLoader: {\n    markdownItPlugins: [\n      require.resolve('markdown-it-anchor'),\n      [require.resolve('markdown-it-table-of-contents'), { containerClass: 'my-container-class' }]\n    ]\n  },\n  {...more}\n};\n```\n\n### Styling and Interaction\n\n#### Container Styling\n\nThe container will have supplied `className` and `style` props passed through to it.\n\n#### Inner Element Styling\n\nIf `passElementProps` is set to `true`, elements within the Markdown Component can be styled on a per-element-name basis. You can set this in the `webpack.config.js` (see the \"Extra Configuration\" section).\n\nAll generated standard elements (read: elements which are known to `React.DOM`) will then have `elementProps['name']` spread onto them (where `name` is the tag name of the element). This option is intended to be used with [Basscss](http://www.basscss.com/) modular CSS.\n\nHere's the above example markdown document converted with this option;\n\n```javascript\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport { name, version } from './package.json';\n\nMarkdownComponent.propTypes = {\n  className: PropTypes.string,\n  style: PropTypes.object,\n  elementProps: PropTypes.object\n};\n\nMarkdownComponent.defaultProps = {\n  elementProps: {}\n};\n\nMarkdownComponent['displayName'] = 'MarkdownComponentLoaderReadme';\n\nfunction MarkdownComponent(props) {\n  const {className, style, elementProps} = props;\n\n  return (\n    \u003cdiv className={className} style={style}\u003e\n      \u003cp {...elementProps['p']}\u003eThis is a \u003cem {...elementProps['em']}\u003eMarkdown Component\u003c/em\u003e file. Here you can include JSX-style assignment expressions; this component was generated using version { version } of { name }!\u003c/p\u003e\n      \u003cp {...elementProps['p']}\u003eProps passed to this component are available as \u003ccode {...elementProps['code']}\u003eprops\u003c/code\u003e, so you can embed those too! Hello there, { props.who || 'world' }!\u003c/p\u003e\n      \u003cp {...elementProps['p']}\u003eAnother cool thing you can do is use JSX \u003cstrong {...elementProps['strong']}\u003edirectly\u003c/strong\u003e - here’s an SVG element, used inline: \u003csvg style={{ display: 'inline', height: '1em' }} viewBox=\"0 0 304 290\" {...elementProps['svg']}\u003e\u003cpath fill=\"none\" stroke=\"currentColor\" strokeWidth=\"16\" d=\"M2,111 h300 l-242.7,176.3 92.7,-285.3 92.7,285.3 z\" {...elementProps['path']} /\u003e\u003c/svg\u003e.\u003c/p\u003e\n    \u003c/div\u003e\n  );\n};\n\nexport default MarkdownComponent;\n\n```\n\nYou can then specify _any_ prop you want here, and that prop will be applied to all elements of that tag name.\n\nFor example, if you wanted to get a callback from each level-1 heading instance, you could use the component like this;\n\n```javascript\n\u003cSomeMarkdownComponent\n  elementProps={{\n    h1: {\n      onClick: (evt) =\u003e /* do something */\n    }\n  }}\n/\u003e\n```\n\nThis also facilitates the Basscss style, allowing, for instance, styling of anchor tags like so;\n\n```javascript\n\u003cSomeMarkdownComponent\n  elementProps={{\n    a: {\n      className: 'blue hover-navy text-decoration-none hover-underline'\n    }\n  }}\n/\u003e\n```\n\n## Prior Art\n\n[react-markdown-loader](https://github.com/javiercf/react-markdown-loader) by Javier Cubides allows use of React components within fenced code blocks (albeit not assignment expressions), and gave me the idea to use yaml front-matter for imports. Thanks! 😁\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fticky%2Fmarkdown-component-loader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fticky%2Fmarkdown-component-loader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fticky%2Fmarkdown-component-loader/lists"}