Skip to content
This repository was archived by the owner on Apr 28, 2026. It is now read-only.

Commit 9ab214a

Browse files
authored
Update Markdown docs for reflex-dev/reflex#6085 (#1730)
* Updates for react-markdown 10.0.0 and associated reflex changes * Update markdown docs with info on plugins * fix misrendered nested code blocks in markdown examples * update deps * update pyproject.toml * Robust slugify of markdown header data You can now include nested markdown in headers and it will slugify it correctly using hast-util-to-string to properly extract recursively nested elements. Also includes a driveby fix for scroll-margin when the hosting banner is displayed.
1 parent 756e024 commit 9ab214a

4 files changed

Lines changed: 777 additions & 587 deletions

File tree

docs/library/typography/markdown.md

Lines changed: 93 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,19 @@ rx.markdown("Pythagorean theorem: $a^2 + b^2 = c^2$.")
3535

3636
You can render code blocks with syntax highlighting using the \`\`\`\{language} syntax:
3737

38-
```python demo
38+
````python demo
3939
rx.markdown(
4040
r"""
41-
\```python
41+
```python
4242
import reflex as rx
4343
from .pages import index
4444
4545
app = rx.App()
4646
app.add_page(index)
47-
\```
47+
```
4848
"""
4949
)
50-
```
50+
````
5151

5252
## Tables
5353

@@ -64,6 +64,86 @@ rx.markdown(
6464
)
6565
```
6666

67+
## Plugins
68+
69+
Plugins can be used to extend the functionality of the markdown renderer.
70+
71+
By default Reflex uses the following plugins:
72+
- `remark-gfm` for Github Flavored Markdown support (`use_gfm`).
73+
- `remark-math` and `rehype-katex` for math equation support (`use_math`, `use_katex`).
74+
- `rehype-unwrap-images` to remove paragraph tags around images (`use_unwrap_images`).
75+
- `rehype-raw` to render raw HTML in markdown (`use_raw`). NOTE: in a future release this will be disabled by default for security reasons.
76+
77+
These default plugins can be disabled by passing `use_[plugin_name]=False` to the `rx.markdown` component. For example, to disable raw HTML rendering, use `rx.markdown(..., use_raw=False)`.
78+
79+
## Arbitrary Plugins
80+
81+
You can also add arbitrary remark or rehype plugins using the `remark_plugins`
82+
and `rehype_plugins` props in conjunction with the `rx.markdown.plugin` helper.
83+
84+
`rx.markdown.plugin` takes two arguments:
85+
86+
1. The npm package name and version of the plugin (e.g. `remark-emoji@5.0.2`).
87+
2. The named export to use from the plugin (e.g. `remarkEmoji`).
88+
89+
### Remark Plugin Example
90+
91+
For example, to add support for emojis using the `remark-emoji` plugin:
92+
93+
```python demo
94+
rx.markdown(
95+
"Hello :smile:! :rocket: :tada:",
96+
remark_plugins=[
97+
rx.markdown.plugin("remark-emoji@5.0.2", "remarkEmoji"),
98+
],
99+
)
100+
```
101+
102+
### Rehype Plugin Example
103+
104+
To make `rehype-raw` safer for untrusted HTML input we can use `rehype-sanitize`, which defaults to a safe schema similar to that used by Github.
105+
106+
```python demo
107+
rx.markdown(
108+
"""Here is some **bold** text and a <script>alert("XSS Attack!")</script>.""",
109+
use_raw=True,
110+
rehype_plugins=[
111+
rx.markdown.plugin("rehype-sanitize@5.0.1", "rehypeSanitize"),
112+
],
113+
)
114+
```
115+
116+
### Plugin Options
117+
118+
Both `remark_plugins` and `rehype_plugins` accept a heterogeneous list of `plugin`
119+
or tuple of `(plugin, options)` in case the plugin requires some kind of special
120+
configuration.
121+
122+
For example, `rehype-slug` is a simple plugin that adds ID attributes to the
123+
headings, but the `rehype-autolink-headings` plugin accepts options to specify
124+
how to render the links to those anchors.
125+
126+
```python demo
127+
rx.markdown(
128+
"""
129+
# Heading 1
130+
## Heading 2
131+
""",
132+
rehype_plugins=[
133+
rx.markdown.plugin("rehype-slug@6.0.0", "rehypeSlug"),
134+
(
135+
rx.markdown.plugin("rehype-autolink-headings@7.1.0", "rehypeAutolinkHeadings"),
136+
{
137+
"behavior": "wrap",
138+
"properties": {
139+
"className": ["heading-link"],
140+
},
141+
},
142+
),
143+
],
144+
)
145+
```
146+
67147
## Component Map
68148

69149
You can specify which components to use for rendering markdown elements using the
@@ -73,17 +153,17 @@ Each key in the `component_map` prop is a markdown element, and the value is
73153
a function that takes the text of the element as input and returns a Reflex component.
74154

75155
```md alert
76-
The `codeblock` and `a` tags are special cases. In addition to the `text`, they also receive a `props` argument containing additional props for the component.
156+
The `pre` and `a` tags are special cases. In addition to the `text`, they also receive a `props` argument containing additional props for the component.
77157
```
78158

79-
```python demo exec
159+
````python demo exec
80160
component_map = {
81161
"h1": lambda text: rx.heading(text, size="5", margin_y="1em"),
82162
"h2": lambda text: rx.heading(text, size="3", margin_y="1em"),
83163
"h3": lambda text: rx.heading(text, size="1", margin_y="1em"),
84164
"p": lambda text: rx.text(text, color="green", margin_y="1em"),
85165
"code": lambda text: rx.code(text, color="purple"),
86-
"codeblock": lambda text, **props: rx.code_block(text, **props, theme=rx.code_block.themes.dark, margin_y="1em"),
166+
"pre": lambda text, **props: rx.code_block(text, **props, theme=rx.code_block.themes.dark, margin_y="1em"),
87167
"a": lambda text, **props: rx.link(text, **props, color="blue", _hover={"color": "red"}),
88168
}
89169

@@ -99,15 +179,17 @@ r"""
99179
100180
Here is some `code`:
101181
102-
\```python
182+
```python
103183
import reflex as rx
104184
105185
component = rx.text("Hello World!")
106-
\```
186+
```
107187
108-
And then some more text here, followed by a link to [Reflex](https://reflex.dev/).
188+
And then some more text here,
189+
followed by a link to
190+
[Reflex](https://reflex.dev/).
109191
""",
110192
component_map=component_map,
111193
)
112194
)
113-
```
195+
````

pcweb/flexdown.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,17 @@ class DemoBlockDark(DemoBlock):
408408
theme = "dark"
409409

410410

411+
class DemoBlockNestedMarkdown(DemoBlock):
412+
"""Used when the block contains literal markdown with triple backticks."""
413+
414+
starting_indicator = "````python demo"
415+
ending_indicator = "````"
416+
417+
418+
class DemoBlockNestedMarkdownDark(DemoBlockNestedMarkdown):
419+
theme = "dark"
420+
421+
411422
class VideoBlock(flexdown.blocks.MarkdownBlock):
412423
"""A block that displays a video."""
413424

@@ -602,11 +613,11 @@ def render(self, env) -> rx.Component:
602613
"li": lambda text: list_comp(text=text),
603614
"a": doclink2,
604615
"code": lambda text: code_comp(text=text),
605-
"codeblock": code_block_markdown,
616+
"pre": code_block_markdown,
606617
"img": lambda src: img_comp_xd(src=src),
607618
}
608619
comp2 = component_map.copy()
609-
comp2["codeblock"] = code_block_markdown_dark
620+
comp2["pre"] = code_block_markdown_dark
610621
comp2["ul"] = lambda items: unordered_list_comp(items=items)
611622
comp2["ol"] = lambda items: ordered_list_comp(items=items)
612623

@@ -615,6 +626,7 @@ def render(self, env) -> rx.Component:
615626
block_types=[
616627
DemoOnly,
617628
DemoBlock,
629+
DemoBlockNestedMarkdown,
618630
AlertBlock,
619631
DefinitionBlock,
620632
SectionBlock,
@@ -628,6 +640,7 @@ def render(self, env) -> rx.Component:
628640
xd2 = flexdown.Flexdown(
629641
block_types=[
630642
DemoBlockDark,
643+
DemoBlockNestedMarkdownDark,
631644
AlertBlock,
632645
DefinitionBlock,
633646
SectionBlock,
@@ -659,6 +672,6 @@ def markdown_with_shiki(*args, **kwargs):
659672
"""
660673
return rx.markdown(
661674
*args,
662-
component_map={"codeblock": markdown_codeblock},
675+
component_map={"pre": markdown_codeblock},
663676
**kwargs,
664677
)

0 commit comments

Comments
 (0)