Markdown
WdMarkdown
Applicable Scenarios
The markdown display component implemented based on markdown-it.
Basic Capabilities Description
- Supports markdown syntax
- Initialization with presets and options, passing preset options via the options parameter.
({
html: html: false, // Enable HTML tags in the source code
xhtmlOut: xhtmlOut: false, // Use / to close single tags (e.g., <br />).
// This option is only compatible with the full CommonMark mode.
breaks: breaks: false, // Convert line breaks in paragraphs to <br> tags.
langPrefix: langPrefix: 'language-', // The CSS language prefix for fenced code blocks. Useful for additional code highlighting.
linkify: linkify: false, // Automatically convert URL-like text to links.
// Enable some language-neutral replacements + quote beautification
typographer: false,
// Double + single quotes replacement pairs, when typographer is enabled.
// Or smart quotes, etc., which can be a String or Array.
//
// For example, you can support '«»„"' for Russians, '„"‚‘' for Germans.
quotes: '""‘’',
});
Extended Scenarios Description
1. How to Use Mermaid in Markdown
Mermaid is a JavaScript-based open-source library that enables users to quickly generate various diagrams—including flowcharts, sequence diagrams, Gantt charts, and mind maps—through concise text and code syntax.
- Load Mermaid

<script src="https://cdn.jsdelivr.net/npm/mermaid@10.9.1/dist/mermaid.min.js"></script>
Domestic cdn address:
<script src="https://cdn.staticfile.net/mermaid/10.7.0/mermaid.min.js"></script>
- Currently, loading external resources is only supported on the Web side and not yet available for mini-programs.
- In some cases, the CDN of jsdeliver on which hosted scripts depend cannot be accessed domestically, resulting in the scripts not being properly enabled. Consider using other CDNs.
- Create the method mermaidRun
export default function ({ event, data }) {
setTimeout(() => {
mermaid.run({
querySelector: '.language-mermaid',
});
}, 0);
}
- Call the mermaidRun method in the markdownReady event to render the diagram
- Write markdown
```mermaid graph TD A[Christmas] -->|Get money| B(Go shopping) B --> C{Let me think} C -->|One| D[Laptop] C -->|Two| E[iPhone] C -->|Three| F[Car] ```

How to use katex in Markdown
katex is a fast, easy-to-use JavaScript library for TeX math rendering on the Web. katex rendering can be supported by loading the katex plugin.
- Load katex

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css" integrity="sha384-nB0miv6/jRmo5UMMR1wu3Gz6NLsoTkbqJghGIsx//Rlm+ZU03BU6SQNC66uf4l5+" crossorigin="anonymous">
<!-- The loading of KaTeX is deferred to speed up page rendering -->
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js" integrity="sha384-7zkQWkzuo3B5mTepMUcHkMB5jZaolc2xDwL6VFqjFALcbeS9Ggm/Yr2r3Dy4lfFg" crossorigin="anonymous"></script>
- Currently, loading external resources is only supported on the Web side and not yet available for mini-programs.
- In some cases, the CDN of jsdeliver on which hosted scripts depend cannot be accessed domestically, resulting in the scripts not being properly enabled.
- Create the katex plugin method
var katex = window.katex;
// Test if potential opening or closing delimieter
// Assumes that there is a "$" at state.src[pos]
function isValidDelim(state, pos) {
var prevChar,
nextChar,
max = state.posMax,
can_open = true,
can_close = true;
prevChar = pos > 0 ? state.src.charCodeAt(pos - 1) : -1;
nextChar = pos + 1 <= max ? state.src.charCodeAt(pos + 1) : -1;
// Check non-whitespace conditions for opening and closing, and
// check that closing delimeter isn't followed by a number
if (
prevChar === 0x20 /* " " */ ||
prevChar === 0x09 /* \t */ ||
(nextChar >= 0x30 /* "0" */ && nextChar <= 0x39) /* "9" */
) {
can_close = false;
}
if (nextChar === 0x20 /* " " */ || nextChar === 0x09 /* \t */) {
can_open = false;
}
return {
can_open: can_open,
can_close: can_close,
};
}
function math_inline(state, silent) {
var start, match, token, res, pos, esc_count;
if (state.src[state.pos] !== '$') {
return false;
}
res = isValidDelim(state, state.pos);
if (!res.can_open) {
if (!silent) {
state.pending += '$';
}
state.pos += 1;
return true;
}
// First check for and bypass all properly escaped delimieters
// This loop will assume that the first leading backtick can not
// be the first character in state.src, which is known since
// we have found an opening delimieter already.
start = state.pos + 1;
match = start;
while ((match = state.src.indexOf('$', match)) !== -1) {
// Found potential $, look for escapes, pos will point to
// first non escape when complete
pos = match - 1;
while (state.src[pos] === '\\') {
pos -= 1;
}
// Even number of escapes, potential closing delimiter found
if ((match - pos) % 2 == 1) {
break;
}
match += 1;
}
// No closing delimter found. Consume $ and continue.
if (match === -1) {
if (!silent) {
state.pending += '$';
}
state.pos = start;
return true;
}
// Check if we have empty content, ie: $$. Do not parse.
if (match - start === 0) {
if (!silent) {
state.pending += '$$';
}
state.pos = start + 1;
return true;
}
// Check for valid closing delimiter
res = isValidDelim(state, match);
if (!res.can_close) {
if (!silent) {
state.pending += '$';
}
state.pos = start;
return true;
}
if (!silent) {
token = state.push('math_inline', 'math', 0);
token.markup = '$';
token.content = state.src.slice(start, match);
}
state.pos = match + 1;
return true;
}
function math_block(state, start, end, silent) {
var firstLine,
lastLine,
next,
lastPos,
found = false,
token,
pos = state.bMarks[start] + state.tShift[start],
max = state.eMarks[start];
if (pos + 2 > max) {
return false;
}
if (state.src.slice(pos, pos + 2) !== '$$') {
return false;
}
pos += 2;
firstLine = state.src.slice(pos, max);
if (silent) {
return true;
}
if (firstLine.trim().slice(-2) === '$$') {
// Single line expression
firstLine = firstLine.trim().slice(0, -2);
found = true;
}
for (next = start; !found; ) {
next++;
if (next >= end) {
break;
}
pos = state.bMarks[next] + state.tShift[next];
max = state.eMarks[next];
if (pos < max && state.tShift[next] < state.blkIndent) {
// non-empty line with negative indent should stop the list:
break;
}
if (state.src.slice(pos, max).trim().slice(-2) === '$$') {
lastPos = state.src.slice(0, max).lastIndexOf('$$');
lastLine = state.src.slice(pos, lastPos);
found = true;
}
}
state.line = next + 1;
token = state.push('math_block', 'math', 0);
token.block = true;
token.content =
(firstLine && firstLine.trim() ? firstLine + '\n' : '') +
state.getLines(start + 1, next, state.tShift[start], true) +
(lastLine && lastLine.trim() ? lastLine : '');
token.map = [start, state.line];
token.markup = '$$';
return true;
}
export default function math_plugin(md, options) {
// Default options
options = options || {};
// set KaTeX as the renderer for markdown-it-simplemath
var katexInline = function (latex) {
options.displayMode = false;
try {
return katex.renderToString(latex, options);
} catch (error) {
if (options.throwOnError) {
console.log(error);
}
return latex;
}
};
var inlineRenderer = function (tokens, idx) {
return katexInline(tokens[idx].content);
};
var katexBlock = function (latex) {
options.displayMode = true;
try {
return '<p>' + katex.renderToString(latex, options) + '</p>';
} catch (error) {
if (options.throwOnError) {
console.log(error);
}
return latex;
}
};
var blockRenderer = function (tokens, idx) {
return katexBlock(tokens[idx].content) + '\n';
};
md.inline.ruler.after('escape', 'math_inline', math_inline);
md.block.ruler.after('blockquote', 'math_block', math_block, {
alt: ['paragraph', 'reference', 'blockquote', 'list'],
});
md.renderer.rules.math_inline = inlineRenderer;
md.renderer.rules.math_block = blockRenderer;
}
- Use the plugin to call the method for updating the markdown instance in the markdownReady event
$w.markdown2.markdownInstance?.use($w.page.handler.katex);
- Write markdown
# Maxwell's Equations
equation | description
----------|------------
$\nabla \cdot \vec{\mathbf{B}} = 0$ | divergence of $\vec{\mathbf{B}}$ is zero
$\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} = \vec{\mathbf{0}}$ | curl of $\vec{\mathbf{E}}$ is proportional to the rate of change of $\vec{\mathbf{B}}$
$\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} = \frac{4\pi}{c}\vec{\mathbf{j}} \nabla \cdot \vec{\mathbf{E}} = 4 \pi \rho$ | _wha?_

Property Introduction
External properties received by the component
Property Name | Property Identifier | Type | Description |
|---|
| Content | value | string | markdown display content Example: "---\n__Advertisement :)__\n\n- __[pica](https://nodeca.github.io/pica/demo/)__ - high quality and fast image\n resize in browser.\n- __[babelfish](https://github.com/nodeca/babelfish/)__ - developer friendly\n i18n with plurals support and easy syntax.\n\nYou will like those projects!\n\n---\n\n# h1 Heading 8-)\n## h2 Heading\n### h3 Heading\n#### h4 Heading\n##### h5 Heading\n###### h6 Heading\n\n\n## Horizontal Rules\n\n___\n\n---\n\n***\n\n\n## Typographic replacements\n\nEnable typographer option to see result.\n\n(c) (C) (r) (R) (tm) (TM) (p) (P) +-\n\ntest.. test... test..... test?..... test!....\n\n!!!!!! ???? ,, -- ---\n\n\"Smartypants, double quotes\" and 'single quotes'\n\n\n## Emphasis\n\n**This is bold text**\n\n__This is bold text__\n\n*This is italic text*\n\n_This is italic text_\n\n~~Strikethrough~~\n\n\n## Blockquotes\n\n\n> Blockquotes can also be nested...\n>> ...by using additional greater-than signs right next to each other...\n> > > ...or with spaces between arrows.\n\n\n## Lists\n\nUnordered\n\n+ Create a list by starting a line with `+`, `-`, or `*`\n+ Sub-lists are made by indenting 2 spaces:\n - Marker character change forces new list start:\n * Ac tristique libero volutpat at\n + Facilisis in pretium nisl aliquet\n - Nulla volutpat aliquam velit\n+ Very easy!\n\nOrdered\n\n1. Lorem ipsum dolor sit amet\n2. Consectetur adipiscing elit\n3. Integer molestie lorem at massa\n\n\n1. You can use sequential numbers...\n1. ...or keep all the numbers as `1.`\n\nStart numbering with offset:\n\n57. foo\n1. bar\n\n\n## Code\n\nInline `code`\n\nIndented code\n\n // Some comments\n line 1 of code\n line 2 of code\n line 3 of code\n\n\nBlock code \"fences\"\n\n```\nSample text here...\n```\n\nSyntax highlighting\n\n``` js\nvar foo = function (bar) {\n return bar++;\n};\n\nconsole.log(foo(5));\n```\n\n## Tables\n\n| Option | Description |\n| ------ | ----------- |\n| data | path to data files to supply the data that will be passed into templates. |\n| engine | engine to be used for processing templates. Handlebars is the default. |\n| ext | extension to be used for dest files. |\n\nRight aligned columns\n\n| Option | Description |\n| ------:| -----------:|\n| data | path to data files to supply the data that will be passed into templates. |\n| engine | engine to be used for processing templates. Handlebars is the default. |\n| ext | extension to be used for dest files. |\n\n\n## Links\n\n[link text](http://dev.nodeca.com)\n\n[link with title](http://nodeca.github.io/pica/demo/ \"title text!\")\n\nAutoconverted link https://github.com/nodeca/pica (enable linkify to see)\n\n\n## Images\n\n\n" |
| Option | options | object | SDK initialization configuration |
Events
Events exposed by the component. You can listen to component events to trigger external actions
Event Name | Event Code | Event Output Parameters event.detail | Applicable Scenarios | Description |
|---|
| markdown Ready | onReady | object
| Compatible with all platforms | The current markdown has completed instance initialization. You can call the markdown instance method. |
Properties API
Through the Property API, you can access the internal state and property values of components. You can access internal values using$w.componentId.propertyName, such as $w.input1.value. For details, please refer to Property API
Read-only Property Name | Property Identifier | Type | Description |
|---|
| Content | value | string | markdown display content |
| markdown instance | markdownInstance | object | 可以通过markdown实例调用markdown实例方法,如:markdownInstance.render("# markdown-it rulezz!")具体内容见markdown-it官方文档 |
Method API
Through the Method API, you can programmatically trigger internal methods of components, such as submitting forms, displaying popups, etc. You can call component methods using $w.componentId.methodName, such as $w.form1.submit()
Method Name | Method Identifier | Parameters | Method Description |
|---|
| Refresh a markdown instance | updateMarkdownInstance | object
| Refresh a markdown instance |
Style API
Through the Style API, you can override the styles of internal elements in components to achieve customization. For example, in the low-code editor, you can write styles for all button components using #wd-page-root .wd-btn, and control individual component styles with :scope. For detailed instructions, please refer toStyle API
Name | Class Name | Description and Examples |
|---|
| root element | .wd-markdown | link component root element |
| PC-side root element link | .wd-pc-markdown | Write styles for PC URLs |
| H5 root element link | .wd-h5-markdown | Write style for H5 URLs |
| Mini program link root element | .wd-mp-markdown | Can write styles for URLs in the mini program |
Limits Description
The markdown display in Mini Programs is achieved by parsing markdown into html using markdown-it, and then rendering it via the Mini Program's rich-text component. Therefore, the markdown rendering capability in Mini Programs is limited, with some styling details differing slightly from the web version. Please refer to the actual runtime effects in the Mini Program for accuracy.
Frequently Asked Questions
Why do externally linked images display abnormally?
Many websites' images verify the page referrer, likely due to enabled hotlink protection. When accessed directly, there's no referrer source, but when used on your page, access may be blocked by referrer verification. You may try alternative image resources or check the loading failure messages in F12 developer tools.