## RichTextEditor A TipTab based rich text editor . Category: Inputs ### Tiptap editor The `RichTextEditor` component is built on top of the [Tiptap editor](https://tiptap.dev/api/editor) For more information see the documentation on [tiptap.dev](https://tiptap.dev) website. Tiptap version note: - DMC 2.4.1 uses Tiptap v3.14.0. - DMC 2.3.0–2.4.0 use Tiptap v3.3. There are no known breaking changes; however, review the migration guide for details. - DMC versions prior to 2.3.0 use Tiptap v2.9. ```python import dash_mantine_components as dmc content = """

Welcome to Mantine rich text editor

RichTextEditor component focuses on usability and is designed to be as simple as possible to bring a familiar editing experience to regular users. RichTextEditor is based on Tiptap.dev and supports all of its features:

""" component = dmc.RichTextEditor( html=content, toolbar={ "sticky": True, "controlsGroups": [ [ "Bold", "Italic", "Underline", "Strikethrough", "ClearFormatting", "Highlight", "Code", ], ["H1", "H2", "H3", "H4"], [ "Blockquote", "Hr", "BulletList", "OrderedList", "Subscript", "Superscript", ], ["Link", "Unlink"], ["AlignLeft", "AlignCenter", "AlignJustify", "AlignRight"], ["Undo", "Redo"], ], }, ) ``` ### Editing Shortcuts: - Keyboard Shortcuts: - Utilize [Tiptap’s keyboard shortcuts](https://tiptap.dev/docs/editor/core-concepts/keyboard-shortcuts#text-formatting) for quick text formatting. - Markdown Shortcuts: - Markdown-style formatting is supported. For example: - Use `#` followed by a space for headings. - Use `-` or `*` for bullet lists. - See the full list of [Markdown shortcuts](https://tiptap.dev/docs/examples/basics/markdown-shortcuts#page-title). ### Tiptap Extensions Extensions expand the capabilities of Tiptap in `RichTextEditor`. DMC provides a predefined set of extensions, all enabled by default. You can customize these as needed. Need an extension that’s not included? Open a [feature request on GitHub](https://github.com/snehilvj/dash-mantine-components/issues). We prioritize requests based on popularity and bundle size impact to keep DMC lightweight and efficient. #### Default Extensions By default, all the available extensions are enabled: ```python dmc.RichTextEditor( extensions=[ {"StarterKit": {"codeBlock": False}}, "CodeBlockLowlight", # available in DMC >= 2.4.0 "Superscript", "Subscript", "Highlight", "Table", "TableCell", "TableHeader", "TableRow", {"TextAlign": {"types": ["heading", "paragraph"]}}, {"Placeholder": {"placeholder": "Write or paste content here..."}}, "Color", "TextStyle", "Image", # The following is available in DMC >= 2.3.0 "BackgroundColor", "FontFamily", "FontSize", "LineHeight", # The following is included in StarterKit in DMC >=2.3.0 # "Underline", # "Link", ] ) ``` The `StarterKit` extension includes essential text-editing features such as: - Text Formatting: `Text`, `Bold`, `Italic`, `Strike`, `Code`, `Underline`, `Link` - Headings & Lists: `Heading`, `OrderedList`, `BulletList`, `ListItem` - Structural Elements: `Paragraph`, `Blockquote`, `CodeBlock`, `HardBreak`, `HorizontalRule`, `Document` - Cursor & History Features: `Dropcursor`, `Gapcursor`, `History` - Source Code editing: `SourceCode` #### Customizing Extensions You can modify the enabled extensions by setting the `extensions` prop. This allows you to: - Exclude features you don’t want - Adjust settings for specific extensions Each extension can be defined in two ways: - As a string to use default settings (for example, `"Color"`) - As a dictionary to specify configuration options (for example `{"TextAlign": {"types": ["heading", "paragraph"]}}`) Some features require multiple extensions. For example: - color formatting requires both `"Color"` and `"TextStyle"`. - Tables require `"Table"`, `"TableCell"`, `"TableHeader"`, and `"TableRow"`. At a minimum, ensure that `"StarterKit"` is included: ```python extensions=["StarterKit"] ``` For a full list of extensions and configuration options, refer to the [Tiptap documentation](https://tiptap.dev/docs/extensions). Note: Setting the `extensions` prop replaces the default list, so if you exclude an extension, for example, `"Image"`, that feature will no longer be available. Be sure to include all the features from the default extension that you need. Here are the default `extensions` for corresponding DMC versions. ```python # RichTextEditor default extensions in dmc version V2.4.0 extensions = [ { 'StarterKit': { 'codeBlock': False } }, 'CodeBlockLowlight', 'Superscript', 'Subscript', 'Highlight', 'Table', 'TableCell', 'TableHeader', 'TableRow', { 'Placeholder': { 'placeholder': 'Write or paste content here...' } }, { 'TextAlign': { 'types': ['heading', 'paragraph'] } }, 'Color', 'TextStyle', 'BackgroundColor', 'FontFamily', 'FontSize', 'LineHeight', 'Image', ] ``` ```python # RichTextEditor default extensions in dmc version V2.3.0 extensions = [ 'StarterKit', 'Superscript', 'Subscript', 'Highlight', 'Table', 'TableCell', 'TableHeader', 'TableRow', { 'Placeholder': { 'placeholder': 'Write or paste content here...' } }, { 'TextAlign': { 'types': ['heading', 'paragraph'] } }, 'Color', 'TextStyle', 'BackgroundColor', 'FontFamily', 'FontSize', 'LineHeight', 'Image', ] ``` ```python # RichTextEditor default extensions in dmc version V1.1.0 extensions = [ 'StarterKit', 'Underline', 'Link', 'Superscript', 'Subscript', 'Highlight', 'Table', 'TableCell', 'TableHeader', 'TableRow', {'Placeholder': {'placeholder': 'Write or paste content here...'}}, {'TextAlign': {'types': ['heading', 'paragraph']}}, 'Color', 'TextStyle', 'Image', ] ``` ### Toolbar Controls Customize the toolbar by grouping control icons using the `controlsGroups` parameter. Each nested list within `controlsGroups` represents a separate group of toolbar icons. Note that even if a toolbar icon is not included, features provided by enabled extensions can still be accessed through keyboard shortcuts and Markdown syntax. ```python dmc.RichTextEditor( toolbar={ "controlsGroups": [ [ "Bold", "Italic", "Underline", ], # First group (text formatting) ["H1", "H2", "H3", "H4"], # second group (headings) ] } ) ``` Here are the control icons available for use in the `toolbar`: **Controls included with StarterKit extension:** - H1 - H2 - H3 - H4 - H5 - H6 - BulletList - OrderedList - Bold - Italic - Strikethrough - ClearFormatting - Blockquote - Code - CodeBlock - Hr - Undo - Redo - SourceCode The following is included by default in DMC >=2.3.0: - Link - Unlink - Underline **Controls that require TextAlign extension:** - AlignLeft - AlignRight - AlignCenter - AlignJustify **Controls that require both Color and TextStyle extensions:** - ColorPicker - Color - UnsetColor **Other controls with required extensions:** - Underline requires `Underline` extension in DMC <=2.3.0 - Superscript requires `Superscript` extension - Subscript requires `Subscript` extension - Highlight requires `Highlight` extension ### Typography styles By default, `RichTextEditor` renders content with [TypographyStylesProvider](/components/typographystylesprovider) and some additional styles. You can disable these styles by setting `withTypographyStyles=False`. Then you can add your own CSS files, or style with the Styles API. ```python dmc.RichTextEditor( withTypographyStyles=False ) ``` ### Placeholder To use the placeholder or change the placeholder default text, include (at least) the following extensions: ```python from dash import html import dash_mantine_components as dmc component = dmc.RichTextEditor( extensions=[ "StarterKit", {"Placeholder": {"placeholder": "Write something..."}}, ], ) ``` ### Text color You can use the following toolbar controls to change text color: - `ColorPicker` – allows to pick colors from given predefined color swatches and with `ColorPicker` component - `Color` – allows to apply given color with one click - `UnsetColor` – clears color styles ```python import dash_mantine_components as dmc colorpicker_colors = [ "#25262b", "#868e96", "#fa5252", "#e64980", "#be4bdb", "#7950f2", "#4c6ef5", "#228be6", "#15aabf", "#12b886", "#40c057", "#82c91e", "#fab005", "#fd7e14", ] component = dmc.RichTextEditor( html="Apply some colors to this text", extensions=[ "StarterKit", "Color", "TextStyle", # required when using Color ], toolbar={ "sticky": True, "stickyOffset": 60, "controlsGroups": [ [ {"ColorPicker": {"colors": colorpicker_colors}}, ], [ {"Color": {"color": "red"}}, {"Color": {"color": "green"}}, {"Color": {"color": "blue"}}, ], ["UnsetColor"], ], }, ) ``` ### Table The tables will be styles with a Mantine theme. For more information refer to the [TypographyStylesProvider](/components/typographystylesprovider) section. You can disable these styles by setting `withTypographyStyles=False` To add controls in the toolbar for table features, see the Custom Controls section below. ```python import dash_mantine_components as dmc table = """
Name Description
Cyndi Lauper Singer Songwriter Actress
Bruce Springsteen Singer Songwriter Actor
""" component = dmc.RichTextEditor( html=table, extensions=[ "StarterKit", "Table", "TableCell", "TableHeader", "TableRow", ], ) ``` ### Image ```python import dash_mantine_components as dmc content = """

This is a basic example of implementing images. Drag to re-order.

""" component = dmc.RichTextEditor( html=content, extensions=[ "StarterKit", "Image", ], ) ``` ### Code highlight *New in V2.4.0* To use code highlight you will need to include at least the following extensions: ```python dmc.RichTextEditor( extensions=[ {"StarterKit": {"codeBlock": False}}, "CodeBlockLowlight", # other needed extensions ], ) ``` Note: You must set `{"codeBlock": False}` in the `StarterKit` configuration to prevent a conflict with the more advanced `CodeBlockLowlight` extension. Current supported languages: ts js python/ py css bash / shell text Set language to text to supress code highlighting. If you would like other languages included, please [open a feature request on our GitHub.](https://github.com/snehilvj/dash-mantine-components/issues) ```python import dash_mantine_components as dmc code_example = """import dash_mantine_components as dmc from dash import Dash app = Dash() app.layout = dmc.MantineProvider( dmc.Alert( "Welcome to Dash Mantine Components", title="Hello!", color="violet", ) ) if __name__ == "__main__": app.run(debug=True)""" component= dmc.RichTextEditor( html=f"

Regular paragraph

{code_example}
", extensions=[ {"StarterKit": { "codeBlock": False }}, "CodeBlockLowlight" ], toolbar={ "controlsGroups": [ [ "Bold", "Italic", "Underline", "Strikethrough", "CodeBlock" ], ], }, ) ``` ### Source code mode You can use the `SourceCode` control to see and edit source code of editor content: ```python import dash_mantine_components as dmc content= '

Source code control example

New line with bold text

New line with italic text

' component =dmc.RichTextEditor( html=content, toolbar={ "sticky": True, "controlsGroups": [ ["SourceCode"], [ "Blockquote", "Bold", "Italic", "Underline", "Strikethrough", "ClearFormatting", "Highlight", ], ], }, ) ``` ### Focus *New in V2.4.0* Use the `focus` prop to control the editor's focus state. - `focus=True` - Focus the editor at the current cursor position - `focus=False` - Blur (remove focus from) the editor - `focus="start"` - Focus at the start of the document - `focus="end"` - Focus at the end of the document - `focus=10` - Focus at a specific position (character offset) Positive values start at the beginning of the document - negative values at the end. - `focus="all"` - Focus and select all content **Example:** ```python import dash_mantine_components as dmc from dash import Input, Output, callback, ctx, no_update component = dmc.Box([ dmc.Group([ dmc.Button("Focus Start", id="rte-btn-focus-start"), dmc.Button("Focus End", id="rte-btn-focus-end"), dmc.Button("Blur", id="rte-btn-blur"), ]), dmc.RichTextEditor( id="rte-focus", html="

Click the buttons to control focus.

", ), ]) @callback( Output("rte-focus", "focus"), Input("rte-btn-focus-start", "n_clicks"), Input("rte-btn-focus-end", "n_clicks"), Input("rte-btn-blur", "n_clicks"), prevent_initial_call=True ) def control_focus(start, end, blur): if not ctx.triggered: return no_update button_id = ctx.triggered_id if button_id == "rte-btn-focus-start": return "start" elif button_id == "rte-btn-focus-end": return "end" elif button_id == "rte-btn-blur": return False ``` ### Editable *New in V2.4.0* The `editable` prop controls whether the editor content can be modified. When `editable=False`: - The editor becomes read-only - Users can still select and copy text - The toolbar is automatically hidden ```python import dash_mantine_components as dmc from dash import Input, Output, callback component = dmc.Box([ dmc.Switch( id="rte-toggle-editable", label="Editable", checked=True, ), dmc.RichTextEditor( id="rte-editable", html="

This editor can be toggled between editable and read-only mode.

", editable=True, toolbar={ "controlsGroups": [ [ "Bold", "Italic", "Underline", "Strikethrough", "CodeBlock" ], ], }, ), ]) @callback( Output("rte-editable", "editable"), Input("rte-toggle-editable", "checked"), ) def toggle_editable(checked): return checked ``` ### Sticky toolbar Set `sticky` prop on `RichTextEditor` `toolbar` prop to make toolbar sticky, control top property with `stickyOffset`. For example, in the dmc docs website there is a header with 60px height, in this case we will need to set `stickyOffset=60` to make sticky position correctly with fixed positioned header element. Note the sticky toolbar as you scroll past the example below. ### Subtle Variant `variant="subtle"` removes borders from the controls groups, makes controls larger and reduces spacing of the toolbar: ```python import dash_mantine_components as dmc component = dmc.RichTextEditor( html="Subtle rich text editor variant", extensions=[ "StarterKit", "Highlight", ], toolbar={ "sticky": True, "stickyOffset": 60, "variant": "subtle", "controlsGroups": [ [ "Bold", "Italic", "Underline", "Strikethrough", "ClearFormatting", "Highlight", "Code", ], ], }, ) ``` ### Labels and localization `RichTextEditor` supports changing labels for all controls with labels prop: ```python import dash_mantine_components as dmc colorpicker_colors = [ "#25262b", "#868e96", "#fa5252", "#e64980", "#be4bdb", "#7950f2", "#4c6ef5", ] component = dmc.RichTextEditor( html="Custom button labels", toolbar={ "sticky": True, "stickyOffset": 60, "controlsGroups": [ [ "Bold", "Italic", "Underline", "Strikethrough", "ClearFormatting", "Highlight", "Code", ], [{"ColorPicker": {"colors": colorpicker_colors}}], [ {"Color": {"color": "red"}}, {"Color": {"color": "green"}}, {"Color": {"color": "blue"}}, ], ["UnsetColor"], ], }, labels={ "boldControlLabel": "Make text bold", "italicControlLabel": "Make text bold", "colorPickerControlLabel": "Text color", # label for control in toolbar "colorPickerColorLabel": "Color number: {color}", # include color in label in the color swatch. Use f-string format "colorControlLabel": "Set Text color {color}" # include color in label with f-string format # ...other labels }, ) ``` Most labels are used to add `aria-label` and `title` attributes to the toolbar controls. Some labels support f-string formatting for dynamic values. If you do not provide all labels, then they will be merged with the default labels. Here are all available labels with their defaults: ```python default_labels = { # Controls labels "linkControlLabel": "Link", "colorPickerControlLabel": "Text color", "highlightControlLabel": "Highlight text", "colorControlLabel": "Set text color {color}", # Use f-string format to include color in label "boldControlLabel": "Bold", "italicControlLabel": "Italic", "underlineControlLabel": "Underline", "strikeControlLabel": "Strikethrough", "clearFormattingControlLabel": "Clear formatting", "unlinkControlLabel": "Remove link", "bulletListControlLabel": "Bullet list", "orderedListControlLabel": "Ordered list", "h1ControlLabel": "Heading 1", "h2ControlLabel": "Heading 2", "h3ControlLabel": "Heading 3", "h4ControlLabel": "Heading 4", "h5ControlLabel": "Heading 5", "h6ControlLabel": "Heading 6", "blockquoteControlLabel": "Blockquote", "alignLeftControlLabel": "Align text: left", "alignCenterControlLabel": "Align text: center", "alignRightControlLabel": "Align text: right", "alignJustifyControlLabel": "Align text: justify", "codeControlLabel": "Code", "codeBlockControlLabel": "Code block", "subscriptControlLabel": "Subscript", "superscriptControlLabel": "Superscript", "unsetColorControlLabel": "Unset color", "hrControlLabel": "Horizontal line", "undoControlLabel": "Undo", "redoControlLabel": "Redo", # Task list "tasksControlLabel": "Task list", "tasksSinkLabel": "Decrease task level", "tasksLiftLabel": "Increase task level", # Link editor "linkEditorInputLabel": "Enter URL", "linkEditorInputPlaceholder": "https://example.com/", "linkEditorExternalLink": "Open link in a new tab", "linkEditorInternalLink": "Open link in the same tab", "linkEditorSave": "Save", # Color picker control "colorPickerCancel": "Cancel", "colorPickerClear": "Clear color", "colorPickerColorPicker": "Color picker", "colorPickerPalette": "Color palette", "colorPickerSave": "Save", "colorPickerColorLabel": "Set Text color {color}", # Use f-string format to include color in color swatch label } ``` ### JSON or HTML Content The editor supports content in either [JSON (ProseMirror) or HTML format](https://tiptap.dev/docs/editor/core-concepts/schema). You can specify the format using the `json` or `html` prop. If both props are set, `json` takes precedence. Note: While users can type Markdown-style text into `RichTextEditor`, the component does not parse or render supplied text in Markdown content. To render Markdown text, use the `dcc.Markdown` component instead. #### When to Use Each Format: - **JSON (ProseMirror)**: Ideal for structured data storage (databases, APIs) or programmatic content manipulation (e.g., dynamically adding elements). - **HTML**: Useful for direct rendering in a browser, email clients, or using with components like `dcc.Markdown`. Note that the schema is very strict. For example, if you use `This is important`, but don’t have any [extension](/components/richtexteditor#tiptap-extensions) that handles strong tags, you’ll only see `This is important` – without the bold formatting.. For details on the schema and ProseMirror format, see the [Tiptap documentation](https://tiptap.dev/docs/editor/core-concepts/schema). Try editing the content in this example to see the JSON and HTML format: ```python from dash import Input, Output, html, callback import dash_mantine_components as dmc content = """

Welcome to Mantine rich text editor

""" component = html.Div( [ dmc.RichTextEditor( html=content, extensions=[ "StarterKit", ], toolbar={ "controlsGroups": [ [ "Bold", "Italic", "Underline", "Strikethrough", ], ], }, id="rte-content", ), dmc.Text("html content:", mt="lg"), dmc.Paper(id="rte-content-html", withBorder=True, mb="lg", p="md"), dmc.Text("json content:"), dmc.Paper(id="rte-content-json", withBorder=True, p="md"), ] ) @callback(Output("rte-content-html", "children"), Input("rte-content", "html")) def update_content(content: str): return f"{content}" @callback(Output("rte-content-json", "children"), Input("rte-content", "json")) def update_content(content: str): return f"{content}" ``` ### Custom controls Use `CustomControl` in the `controlsGroups` to create create custom controls in the `toolbar`. Note that you will need to set `aria-label` attribute to make control visible for screen readers. Tiptap version note: - DMC 2.3.0 and later uses [Tiptap v3.3 commands](https://tiptap.dev/docs/editor/api/commands). - Older versions of DMC used [Tiptap v2.9 commands](https://v2.tiptap.dev/docs/editor/api/commands). Use the appropriate Tiptap documentation above to see the full list of editor commands available for your custom controls. Note: This example uses custom JavaScript defined in the assets folder. Learn more in the "Functions As Props" section of this document. #### Example: Insert content ```python import dash_mantine_components as dmc from dash_iconify import DashIconify component = dmc.RichTextEditor( html= '
Click control to insert star emoji
', toolbar = { "controlsGroups": [ [ { "CustomControl": { "aria-label": "Custom Button", "title": "Custom Button", "children": DashIconify(icon="mdi:star", width=20, height=20), "onClick": {"function": "insertContent", "options": "⭐"}, }, }, ], ], }, ) ``` ```javascript var dmcfuncs = window.dashMantineFunctions = window.dashMantineFunctions || {}; dmcfuncs.insertContent = ({editor}, options) => { editor?.commands.insertContent(options) } ``` #### Example: Table controls ```python import dash_mantine_components as dmc from dash_iconify import DashIconify toolbar = { "sticky": True, "controlsGroups": [ [ { "CustomControl": { "aria-label": "Insert Table", "title": "Insert Table", "children": [DashIconify(icon="mdi:table-plus", width=20, height=20)], "onClick": {"function": "insertTable"}, }, }, { "CustomControl": { "aria-label": "Add Column Before", "title": "Add Column Before", "children": [DashIconify(icon="mdi:table-column-plus-before", width=20, height=20)], "onClick": {"function": "addColumnBefore"}, }, }, { "CustomControl": { "aria-label": "Delete Column", "title": "Delete Column", "children": [DashIconify(icon="mdi:table-column-remove", width=20, height=20)], "onClick": {"function": "deleteColumn"}, }, }, ], [ "Bold", "Italic", "Underline", ], ], } component = dmc.RichTextEditor( html= '
Click controls to insert table, add column before, or delete column
', toolbar = toolbar, className="rte" # applies custom table styles to this component only ) ``` ```javascript var dmcfuncs = window.dashMantineFunctions = window.dashMantineFunctions || {}; dmcfuncs.insertTable = ({editor}) => { editor?.chain().focus().insertTable({ rows: 5, cols: 3, withHeaderRow: true }).run() } dmcfuncs.addColumnBefore = ({editor}) => { editor?.chain().focus().addColumnBefore().run() } dmcfuncs.deleteColumn= ({editor}) => { editor?.chain().focus().deleteColumn().run() } ``` ```css .rte :is(table, th, td) { border: 1px solid var(--table-border-color); } ``` #### Example: Font size controls *New in V2.3.0* ```python import dash_mantine_components as dmc from dash_iconify import DashIconify component = dmc.RichTextEditor( html="

Change font size with the controls!

", toolbar={ "controlsGroups": [ ["H1", "H2", "H3", "H4"], [ { "CustomControl": { "aria-label": "Increase font size", "title": "Increase font size", "children": DashIconify(icon="mdi:format-font-size-increase", width=16), "onClick": {"function": "increaseFontSize"}, }, }, { "CustomControl": { "aria-label": "Decrease font size", "title": "Decrease font size", "children": DashIconify(icon="mdi:format-font-size-decrease", width=16), "onClick": {"function": "decreaseFontSize"}, }, }, ], ], }, ) ``` ```javascript var dmcfuncs = window.dashMantineFunctions = window.dashMantineFunctions || {}; function changeFontSize(editor, delta) { if (!editor) return; const { from, to } = editor.state.selection; let size = 16; // default editor.state.doc.nodesBetween(from, to, (node) => { if (node.isText) { const mark = node.marks.find(m => m.type.name === "textStyle"); if (mark?.attrs.fontSize) { size = parseInt(mark.attrs.fontSize, 10); } } }); const newSize = Math.min(Math.max(size + delta, 8), 72) + "px"; editor.chain().focus().setFontSize(newSize).run(); } dmcfuncs.increaseFontSize = ({ editor }) => changeFontSize(editor, 2); dmcfuncs.decreaseFontSize = ({ editor }) => changeFontSize(editor, -2); ``` ### Selected text The `selected` prop contains the currently selected text. Note that it is text only and does not include any formatting. ```python from dash import Input, Output, html, callback import dash_mantine_components as dmc component = html.Div( [ dmc.RichTextEditor( html="

Welcome to the editor.

Select some text

", extensions=[ "StarterKit", ], toolbar={ "controlsGroups": [ [ "Bold", "Italic", "Underline", "Strikethrough", "Highlight", ], ] }, id="rte", ), dmc.Box(id="rte-selected", mt="lg"), ] ) @callback(Output("rte-selected", "children"), Input("rte", "selected")) def update_content(content: str): return f"Your selected text: {content}" ``` ### Accessing the Editor Instance clientside The `dash_mantine_components.getEditor(id)` function provides direct access to the underlying Tiptap editor instance in clientside callbacks. This allows you full access to the editor API including executing commands, inspecting content, and updating the editor state. See the [Tiptap editor API](https://tiptap.dev/docs/editor/api/commands) for more details. This returns the Tiptap editor instance for the specified component ID, or `undefined` if the editor doesn't exist: ```javascript const editor = dash_mantine_components.getEditor('editor-id'); ``` This example shows how to access the editor in a clientside callback and provide a word count of the content. ```python import dash_mantine_components as dmc from dash import Dash, Input, Output, clientside_callback component = dmc.Box([ dmc.RichTextEditor( id="get-editor-id", toolbar={ "controlsGroups": [ [ "Bold", "Italic", "Underline", "Strikethrough", ], ], }, html="

Try typing some text in this editor. Click the button below to see your character and word count.

" ), dmc.Button("Get Stats", id="btn-rte-stats", n_clicks=0), dmc.Box(id="stats"), ]) clientside_callback( """ function(n_clicks) { if (n_clicks > 0) { const editor = dash_mantine_components.getEditor('get-editor-id'); if (editor) { const text = editor.getText(); const chars = text.length; const words = text.split(/\\s+/).filter(Boolean).length; return `Characters: ${chars} | Words: ${words}`; } } return dash_clientside.no_update; } """, Output("stats", "children"), Input("btn-rte-stats", "n_clicks"), ) ``` ### Debounce The `debounce` prop controls how updates to the `html`, `json`, and `selected` props are triggered in the `RichTextEditor`. Enabling debounce helps prevent excessive callbacks by delaying updates until the user stops interacting. If set to `True`, updates occur only when the editor loses focus. Alternatively, you can specify a delay in milliseconds to fine-tune when updates should be sent. ```python dmc.RichTextEditor( debounce=500 # # Delay updates by 500ms ) ``` ### Persistence Dash provides built-in persistence props that allow components to retain their values across page reloads or app sessions. In `RichTextEditor`, this means the editor content can be saved and restored automatically. The following persistence-related props are available: - `persistence` – Enables persistence (`True`, `"local"`, `"session"`, or `"memory"`). - `persisted_props` – Specifies which props should be persisted. By default it's `["html, json"]` - `persistence_type` – Defines where the data is stored (`"local"`, `"session"`, or `"memory"`). For more details on how Dash handles persistence, refer to the [Dash persistence documentation](https://dash.plotly.com/persistence). Notes: - The component must have an `id` for persistence to work. - If you want to set an initial value while also enabling persistence, set `persisted_props` to only the prop used for the initial value. For example `persisted_props=['html']`. ### CSS Extensions As of DMC 1.2.0, RichTextEditor component styles are bundled automatically, so you no longer need to include a separate CSS file. If you're using an older version of DMC, refer to the [migration guide](/migration) for instructions on including optional stylesheets. ### Styles API This component supports Styles API. With Styles API, you can customize styles of any inner element. See the Styling and Theming sections of these docs for more information. #### RichTextEditor Selectors | Selector | Static Selector | Description | |----------------------------------|------------------------------------------------------|-------------| | `root` | `.mantine-RichTextEditor-root` | Root element | | `toolbar` | `.mantine-RichTextEditor-toolbar` | Toolbar element | | `content` | `.mantine-RichTextEditor-content` | Content area | | `typographyStylesProvider` | `.mantine-RichTextEditor-typographyStylesProvider` | TypographyStylesProvider component, wraps content | | `control` | `.mantine-RichTextEditor-control` | `RichTextEditor.Control` root element, used as a base for all controls | | `controlIcon` | `.mantine-RichTextEditor-controlIcon` | Control icon element | | `controlsGroup` | `.mantine-RichTextEditor-controlsGroup` | `RichTextEditor.ControlsGroup` component root | | `linkEditor` | `.mantine-RichTextEditor-linkEditor` | Link editor root element | | `linkEditorSave` | `.mantine-RichTextEditor-linkEditorSave` | Link editor save button | | `linkEditorInput` | `.mantine-RichTextEditor-linkEditorInput` | Link editor URL input | | `linkEditorExternalControl` | `.mantine-RichTextEditor-linkEditorExternalControl` | Link editor external button | | `linkEditorDropdown` | `.mantine-RichTextEditor-linkEditorDropdown` | Link editor popover dropdown element | #### RichTextEditor Data Attributes | Selector | Attribute | Condition | |-----------|--------------|---------------------------| | `control` | `data-active` | Control is active | ### Keyword Arguments #### RichTextEditor - id (string; optional): Unique ID to identify this component in Dash callbacks. - aria-* (string; optional): Wild card aria attributes. - attributes (boolean | number | string | dict | list; optional): Passes attributes to inner elements of a component. See Styles API docs. - className (string; optional): Class added to the root element, if applicable. - classNames (dict; optional): Adds custom CSS class names to inner elements of a component. See Styles API docs. - darkHidden (boolean; optional): Determines whether component should be hidden in dark color scheme with `display: none`. - data-* (string; optional): Wild card data attributes. - debounce (number | boolean; optional): If True, changes will be sent back to Dash only when losing focus. If False, data will be sent on every change. If a number, data will be sent when the value has been stable for that number of milliseconds. - editable (boolean; optional): If True, the editor will be editable. True by default. - extensions (list; optional): List of extensions to be loaded by the editor. Each item can be either a string with the extension name (e.g. 'Color') or an object with the extension name as key and options as value (e.g. {'TextAlign': {'types': ['heading', 'paragraph']}}). ['StarterKit', 'Underline', 'Link', 'Superscript', 'Subscript', 'Highlight', 'Table', 'TableCell', 'TableHeader', 'TableRow', {'Placeholder': {'placeholder': 'Write or paste content here...'}}, {'TextAlign': {'types': ['heading', 'paragraph']}}, 'Color', 'TextStyle', 'Image'] by default. - focus (number | boolean; optional): If True, the editor will be focused. If False, the editor will be blurred. Can also be a string ('start', 'end', 'all') or number to focus at a specific position. Positive values start at the beginning of the document - negative values at the end. - hiddenFrom (string; optional): Breakpoint above which the component is hidden with `display: none`. - html (string; optional): HTML string representation of the editor content. Affected by debounce. If both json and html are provided, json takes precedence. - json (dict; optional): JSON object (ProseMirror) representation of the editor content. Affected by debounce. If both json and html are provide, json takes precedence. - labels (dict; optional): Labels that are used in controls. If not set, default labels are used. `labels` is a dict with keys: - lightHidden (boolean; optional): Determines whether component should be hidden in light color scheme with `display: none`. - loading_state (dict; optional): Object that holds the loading state object coming from dash-renderer. For use with dash<3. `loading_state` is a dict with keys: - mod (string | dict | list of string | dicts; optional): Element modifiers transformed into `data-` attributes. For example: "xl" or {"data-size": "xl"}. Can also be a list of strings or dicts for multiple modifiers. Falsy values are removed. - n_blur (number; optional): An integer that represents the number of times that this element has lost focus. - persisted_props (list of strings; optional): Properties whose user interactions will persist after refreshing the component or the page. Since only `value` is allowed this prop can normally be ignored. - persistence (string | number | boolean; optional): Used to allow user interactions in this component to be persisted when the component - or the page - is refreshed. If `persisted` is truthy and hasn't changed from its previous value, a `value` that the user has changed while using the app will keep that change, as long as the new `value` also matches what was given originally. Used in conjunction with `persistence_type`. Note: The component must have an `id` for persistence to work. - persistence_type (a value equal to: 'local', 'session', 'memory'; optional): Where persisted user changes will be stored: memory: only kept in memory, reset on page refresh. local: window.localStorage, data is kept after the browser quit. session: window.sessionStorage, data is cleared once the browser quit. - selected (string; optional): Currently selected text. Affected by debounce. - styles (boolean | number | string | dict | list; optional): Adds inline styles directly to inner elements of a component. See Styles API docs. - tabIndex (number; optional): tab-index. - toolbar (dict; optional): Toolbar property definition. Empty by default. `toolbar` is a dict with keys: - variant (a value equal to: 'default', 'subtle'; optional): Variant of the editor. - visibleFrom (string; optional): Breakpoint below which the component is hidden with `display: none`. - withCodeHighlightStyles (boolean; optional): Determines whether code highlight styles should be added, True by default. - withTypographyStyles (boolean; optional): Determines whether typography styles should be added, True by default.