When to use
Markdown is a document markup language that can implement basic common rich text functions such as titles, pictures, tables, links, bolding, etc. through simple tags. MDX is based on Markdown and allows the introduction of JSX to achieve more complex and customized document writing and display requirements.
The MarkdownRender component provided by Semi supports rendering Markdown and MDX. No special configuration is required. By passing in plain text, rich text content that conforms to Semi style specifications can be rendered. Code blocks are highlighted by CodeHighlight; register the languages they use with CodeHighlight.register first, an unregistered language is shown as plain text.
Usually used in the following scenarios:
- Document site writing and rendering
- Front-end rendering when the server dynamically generates rich text content
- A light interactive website that focuses on content display
Demos
How to import
import { MarkdownRender } from '@fibrous/semi-ui-react';
Basic usage
After importing MarkdownRender, just pass in Markdown or MDX plain text directly.
Note that symbols such as < and { are valid JSX syntax and are treated as code, so they cannot be rendered directly and must be escaped with \. If you only need to render pure Markdown, see the Simple Markdown section below.
Code
import { MarkdownRender } from '@fibrous/semi-ui-react';
export default function MarkdownRenderDemo() {
return (
<MarkdownRender
raw={`
正文内容是普通的文本,也可以**加粗**~~删除线~~和<u>下划线</u> [超链接](https://semi.design) 等 Markdown 与 HTML 的基本语法所支持的富文本,也支持 emoji 🍰
部分符号需要转义 \\{\\} \\<\\> ...
<br/>
<br/>
---
#### Semi Design DSM
[Semi DSM](https://semi.design/dsm) 是 Semi Design 提供的设计系统管理工具(Design System Management),支持全局、组件级别的样式定制,并在 Figma 和前端代码之间保持同步\\
适用于各种规模的团队,无论你是需要简化工作流程,提高团队协作,还是增加生产力,我们都有适合你的功能
##### 中大型企业
- 多达 3000+ Design Token,深入每一处细节的定制可能,色彩,阴影,边距,圆角,动效,渲染结构均可自由定制,告别 ~~CSS 硬编码~~
- 功能强大,经过抖音内部数千项目验证过的 UI lib,轻松应对各类复杂场景
- A11y 无障碍友好,国际化功能完备
- 面向社区建设,完全开源,无使用限制
- 从 designOps 到 devOps,自动化工作流,Figma UI Kit 一键刷入主题,生成 Style Guideline,研发一行 npm 代码配置接入
##### 初创企业
- 无需从 0 到 1 投入大量研发资源,快速复用开源社区优秀方案, 低成本快速定制具备品牌特色的设计系统。
- 一键支持暗色模式生成,支持根据品牌色快速生成包含 320 个全色阶、兼容深/浅两种模式的色彩系统,并支持动态切换
- 不断进化,DSM + Semi Design 组件由<u>抖音前端架构团队</u>专业维护,已稳定迭代五年+,值得信赖
##### 自由设计师/个人开发者
- 低成本快速创建风格各异的设计系统,更少时间,更快交付
- 研发接入友好,无需反复沟通,交付npm包产物,一键完成代码接入

---
#### MarkdownRender 渲染列表语法
- 好好地吃饭
- 好好地睡觉
- 好好地游玩
- 好好地学习
- 好好地聊天
- 好好地吵架
- 过着平凡普通的每日
| 支持 | Markdown 表格 | c | d |
| - | :- | -: | :-: |
| 1 | 2 | 3 | 4 |
| 21 | 22 | 23 | 24 |
| 31 | 32 | 33 | 34 |
| 41 | 42 | 43 | 44 |
`}
/>
);
}Modify element style
You can arbitrarily replace the display effect of document elements in Markdown or MDX documents. Just pass your rendering component override to the components props.
For example, now you need to set the color of all level 2 headings to the main color
Code
import type { ReactNode } from 'react';
import { MarkdownRender, Typography, type MarkdownRenderComponents } from '@fibrous/semi-ui-react';
export default function MarkdownRenderDemo() {
const components: MarkdownRenderComponents = {};
components['h2'] = ({ children }: { children?: ReactNode }) => (
<Typography.Title heading={2} style={{ color: 'var(--semi-color-primary)' }}>
{children}
</Typography.Title>
);
return <MarkdownRender raw="## 从 Semi Design 到 Any Design 快速定义你的设计系统,并应用在设计稿和代码中" components={components} />;
}Any element tag that Markdown generates can be overridden; the common ones are a blockquote br code del em h1 h2 h3 h4 h5 h6 hr img li ol p pre strong ul table
Simple Markdown
When the Markdown you render is just pure markdown without any JSX code, you can pass format="md" to enable Markdown-only mode. In this mode, you don't need to escape special characters.
无需转义的符号{}<> ...
Code
import { MarkdownRender } from '@fibrous/semi-ui-react';
export default function MarkdownRenderDemo() {
return <MarkdownRender raw="无需转义的符号{}<> ..." format="md" />;
}format="md" renders through a unified pipeline: remark-parse parses the source, remark-gfm (when remarkGfm is true) and remarkPlugins run in order, remark-rehype turns it into an HTML syntax tree, rehypePlugins run, and hast-util-to-jsx-runtime creates the React elements with components applied. No code is generated or evaluated, so it renders under a CSP without unsafe-eval, and the MDX compiler is never loaded.
format="mdx" compiles the source to code with @mdx-js/mdx and evaluates it at runtime, so the CSP has to allow unsafe-eval; @mdx-js/mdx is loaded on demand the first time MDX is rendered.
import { MarkdownRender } from '@fibrous/semi-ui-react';
import rehypeRaw from 'rehype-raw';
function Demo() {
return <MarkdownRender format="md" raw={`<span style="color:red">Red text</span>`} rehypePlugins={[rehypeRaw]} />;
}
Add custom components
By passing in custom components to components Props, you can write JSX directly in Markdown, and the component will be rendered to the final page, supporting JS events. The default Markdown components can be obtained from MarkdownRender.defaultComponents and can be used for secondary packaging.
Code
import type { MouseEventHandler, ReactNode } from 'react';
import { Button, MarkdownRender, type MarkdownRenderComponents } from '@fibrous/semi-ui-react';
interface MyButtonProps {
children?: ReactNode;
onClick?: MouseEventHandler<HTMLElement>;
}
export default function MarkdownRenderDemo() {
const components: MarkdownRenderComponents = {};
components['MyButton'] = ({ children, onClick }: MyButtonProps) => {
return (
<Button type="primary" onClick={onClick} style={{ marginBottom: '12px' }}>
{' '}
{children}{' '}
</Button>
);
};
return (
<MarkdownRender
raw={`
#### 下面是一个渲染在 Markdown 中的按钮
<MyButton onClick={()=>alert("点击了 MyButton")}>MyButton 点我</MyButton>
直接在 Markdown 中书写 JSX 即可
`}
components={{ ...MarkdownRender.defaultComponents, ...components }}
/>
);
}Add plugins
Remark and Rehype plugins of the unified ecosystem are supported through remarkPlugins rehypePlugins, please refer to MDXJS and unified for details
The source compiles again when raw, format, remarkGfm or an entry of a plugin array changes; a components change only re-renders. Plugin arrays are compared entry by entry, so an array literal created on every render does not compile again while its entries stay the same. The options object of a [plugin, options] entry is compared by reference too: written as a literal it compiles again on every render, so keep it stable with useMemo:
import { useMemo } from 'react';
import { MarkdownRender } from '@fibrous/semi-ui-react';
import remarkToc from 'remark-toc';
function Demo({ raw }) {
const remarkPlugins = useMemo(() => [[remarkToc, { heading: 'Contents' }]], []);
return <MarkdownRender format="md" raw={raw} remarkPlugins={remarkPlugins} />;
}
Compile errors
When the MDX has a syntax error or a plugin throws, the last successfully rendered content stays on the page and the error is logged with console.error in development; no unhandled Promise rejection is left behind.
Accessibility
With aria-label or aria-labelledby and no role, the root element gets role="group"; a role you pass takes precedence. An image inside a link cannot be previewed, so the link is the only interactive element; the caption under an image is hidden from assistive technology and the image's name comes from alt alone.
API
Props
| Property | Description | Type | Default |
|---|---|---|---|
| className | Class name of the root div element, merged with the component's own class name. | string | - |
| components | Overrides Markdown elements and adds the custom components MDX sources refer to. Values are React components or HTML tag names; an element key such as h1 takes a component or its own tag name. Merged over MarkdownRender.defaultComponents; a change only renders again, it does not compile again. A key whose value is undefined falls back to the built-in component. | MarkdownRenderComponents | - |
| format | Format of raw: md is plain Markdown, mdx allows embedded JSX. Compiles again on change. | 'md' | 'mdx' | "mdx" |
| raw | Markdown or MDX source text. Compiles again on change. | string | - |
| ref | Reference to the root div element. | TypeReact.Ref<HTMLDivElement> | - |
| rehypePlugins | Custom Rehype plugins. Compiles again when an entry changes. | PluggableList | - |
| remarkGfm | Whether to enable GitHub GFM syntax. Compiles again on change. | boolean | true |
| remarkPlugins | Custom Remark plugins. Compiles again when an entry changes. | PluggableList | - |
| style | Style of the root div element. | React.CSSProperties | - |
Other native attributes, such as id, data-*, aria-* and event attributes like onClick, land on the root div.
Design Token
| Sass variable | Value | Usage |
|---|---|---|
| $spacing-markdownRender_component_image-marginLeft | 16px | |
| $spacing-markdownRender_component_image-marginRight | 16px | |
| $spacing-markdownRender_component_image-marginTop | 16px | |
| $spacing-markdownRender_component_image-marginBottom | 16px | |
| $width-markdownRender_component_image-maxWidth | 50% | |
| $width-markdownRender_component_image-maxHeight | 500px | |
| $spacing-markdownRender_component_image_alt-marginTop | 8px | |
| $spacing-markdownRender_component_header1-marginTop | 16px | |
| $spacing-markdownRender_component_header1-marginBottom | 16px | |
| $spacing-markdownRender_component_header2-marginTop | 16px | |
| $spacing-markdownRender_component_header2-marginBottom | 16px | |
| $spacing-markdownRender_component_header3-marginTop | 16px | |
| $spacing-markdownRender_component_header3-marginBottom | 16px | |
| $spacing-markdownRender_component_header4-marginTop | 16px | |
| $spacing-markdownRender_component_header4-marginBottom | 16px | |
| $spacing-markdownRender_component_header5-marginTop | 16px | |
| $spacing-markdownRender_component_header5-marginBottom | 16px | |
| $spacing-markdownRender_component_header6-marginTop | 16px | |
| $spacing-markdownRender_component_header6-marginBottom | 16px | |
| $spacing-markdownRender_component_list-paddingLeft | 24px | |
| $spacing-markdownRender_component_list-marginTop | 16px | |
| $spacing-markdownRender_component_list-marginBottom | 16px | |
| $color-markdownRender_simpleCode-bg | var(--semi-color-fill-0) | |
| $color-markdownRender_simpleCode-text | var(--semi-color-text-1) | |
| $color-markdownRender_component_list | var(--semi-color-text-0) | |
| $color-markdownRender_component_image_alt | var(--semi-color-tertiary) |