apps/mantine.dev/src/pages/x/tiptap.mdx
import { TipTapDemos } from '@docs/demos'; import { Layout } from '@/layout'; import { MDX_DATA } from '@/mdx';
export default Layout(MDX_DATA.TipTap);
Install with yarn:
<InstallScript packages="@mantine/tiptap @mantine/core @mantine/hooks @tiptap/react @tiptap/pm @tiptap/extension-link @tiptap/starter-kit" />After installation import package styles at the root of your application:
import '@mantine/core/styles.css';
// ‼️ import tiptap styles after core package styles
import '@mantine/tiptap/styles.css';
The @mantine/tiptap package provides a UI for Tiptap. The RichTextEditor component
works with the Editor instance of tiptap.
This means that you have full control over the editor state and configuration
with the useEditor hook.
In other words, the RichTextEditor component does not manage state for you;
controls just execute operations on the Editor instance. If you want to
implement something that is related to state or component value (for example, controlled mode, value transforms to HTML/Markdown),
you should look for documentation on the tiptap.dev website.
variant="subtle" removes borders from the control groups, makes controls
larger, and reduces spacing of the toolbar:
To control the editor state, create a wrapper component and pass the onChange handler
to the useEditor hook:
import { useEditor } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import { RichTextEditor as MantineRichTextEditor } from '@mantine/tiptap';
interface RichTextEditorProps {
value: string;
onChange: (value: string) => void;
}
export function RichTextEditor({
value,
onChange,
}: RichTextEditorProps) {
const editor = useEditor({
extensions: [StarterKit],
content: value,
onUpdate: ({ editor }) => {
onChange(editor.getHTML());
},
});
return (
<MantineRichTextEditor editor={editor}>
<MantineRichTextEditor.Toolbar>
<MantineRichTextEditor.ControlsGroup>
<MantineRichTextEditor.Bold />
<MantineRichTextEditor.Italic />
</MantineRichTextEditor.ControlsGroup>
</MantineRichTextEditor.Toolbar>
<MantineRichTextEditor.Content />
</MantineRichTextEditor>
);
}
Some controls require installation of additional Tiptap extensions.
For example, if you want to use RichTextEditor.Superscript control, you will need to install @tiptap/extension-superscript package:
Included with @tiptap/starter-kit (should be installed by default):
RichTextEditor.H1RichTextEditor.H2RichTextEditor.H3RichTextEditor.H4RichTextEditor.H5RichTextEditor.H6RichTextEditor.BulletListRichTextEditor.OrderedListRichTextEditor.BoldRichTextEditor.ItalicRichTextEditor.StrikethroughRichTextEditor.ClearFormattingRichTextEditor.BlockquoteRichTextEditor.CodeRichTextEditor.CodeBlockRichTextEditor.HrRichTextEditor.UndoRichTextEditor.RedoRichTextEditor.UnderlineRichTextEditor.UnlinkControls that require @tiptap/extension-text-align extension:
RichTextEditor.AlignLeftRichTextEditor.AlignRightRichTextEditor.AlignCenterRichTextEditor.AlignJustifyControls that require @tiptap/extension-color and @tiptap/extension-text-style extensions:
RichTextEditor.ColorPickerRichTextEditor.ColorRichTextEditor.UnsetColorOther controls with required extensions:
RichTextEditor.Superscript requires @tiptap/extension-superscriptRichTextEditor.Subscript requires @tiptap/extension-subscriptRichTextEditor.Highlight requires @tiptap/extension-highlightTo use a placeholder, you will need to install the @tiptap/extension-placeholder package:
<InstallScript packages="@tiptap/extension-placeholder" /> <Demo data={TipTapDemos.placeholder} />The @mantine/tiptap package provides a custom Link extension that is required to be used instead of
@tiptap/extension-link in order for the Ctrl + K keyboard shortcut to work:
// Use Link extension exported from the @mantine/tiptap package
import { useEditor } from '@tiptap/react';
import { Link, RichTextEditor } from '@mantine/tiptap';
function Demo() {
const editor = useEditor({
extensions: [
Link,
// ... other extensions
],
});
return (
<RichTextEditor editor={editor}>
<RichTextEditor.Content />
</RichTextEditor>
);
}
To use text color, you will need to install additional packages:
<InstallScript packages="@tiptap/extension-color @tiptap/extension-text-style" />You can use the following controls to change text color:
RichTextEditor.ColorPicker – allows you to pick colors from given predefined color swatches and with the ColorPicker componentRichTextEditor.Color – allows you to apply a given color with one clickRichTextEditor.UnsetColor – clears color stylesTo use code highlighting, you will need to install additional packages:
<InstallScript packages="lowlight @tiptap/extension-code-block-lowlight" /> <Demo data={TipTapDemos.codeHighlight} />You can use the following control to see and edit the source code of editor content:
RichTextEditor.SourceCode – allows switching on/off source code modeTo use tasks, you will need to install additional packages:
<InstallScript packages="@tiptap/extension-task-item @tiptap/extension-task-list" /> <Demo data={TipTapDemos.tasks} />By default, RichTextEditor renders content with Typography and some additional styles.
You can disable these styles by setting withTypographyStyles={false}:
import { useEditor } from '@tiptap/react';
import { RichTextEditor } from '@mantine/tiptap';
function Demo() {
const editor = useEditor({
extensions: [
// ... your extensions
],
});
return (
<RichTextEditor editor={editor} withTypographyStyles={false}>
<RichTextEditor.Content />
</RichTextEditor>
);
}
Then you will be able to add your own styles either with global styles or with Styles API:
<Demo data={TipTapDemos.typographyStyles} />You can use the BubbleMenu component
with any RichTextEditor controls. The bubble menu will appear near a selection of text:
You can use the FloatingMenu component
with any RichTextEditor controls. The floating menu will appear in an empty line:
Set the sticky prop on the RichTextEditor.Toolbar component to make the toolbar sticky;
control the top property with stickyOffset. For example, on the mantine.dev documentation
website there is a header with var(--docs-header-height) height. In this case, we will need to
set stickyOffset="var(--docs-header-height)" to make the sticky position work correctly with the fixed positioned element.
<Demo data={TipTapDemos.usage} demoProps={{ toggle: true }} />
Use the useRichTextEditorContext hook to get the Editor from
the context. This hook can be used to create a custom control or run any operations supported
by the Tiptap editor API.
import { Button } from '@mantine/core';
import { useRichTextEditorContext } from '@mantine/tiptap';
function Demo() {
const { editor } = useRichTextEditorContext();
return (
<Button
onClick={() => editor?.chain().focus().toggleBold().run()}
>
Make bold
</Button>
);
}
Use the RichTextEditor.Control component to create custom controls. It supports all
props supported by the button element and has an active prop to indicate active state.
Note that you will need to set the aria-label attribute to make the control visible for screen readers.
You can change the icon of a control by setting the icon prop. It accepts a component
that must handle the size prop:
RichTextEditor supports changing labels for all controls with the labels prop:
import { useEditor } from '@tiptap/react';
import { RichTextEditor } from '@mantine/tiptap';
function Demo() {
const editor = useEditor({
extensions: [
// ... your extensions
],
});
return (
<RichTextEditor
editor={editor}
labels={{
boldControlLabel: 'Make text bold',
italicControlLabel: 'Make text bold',
// ...other labels
}}
>
<RichTextEditor.Content />
</RichTextEditor>
);
}
Most labels are used to add aria-label and title attributes to controls; some of the labels
can be a function that returns a string. If you do not provide all labels, they will be merged with
the default labels.
All available labels:
// RichTextEditorLabels type can be imported from @mantine/tiptap package
export interface RichTextEditorLabels {
/** RichTextEditor.Bold control aria-label */
boldControlLabel: string;
/** RichTextEditor.Hr control aria-label */
hrControlLabel: string;
/** RichTextEditor.Italic control aria-label */
italicControlLabel: string;
/** RichTextEditor.Underline control aria-label */
underlineControlLabel: string;
/** RichTextEditor.Strike control aria-label */
strikeControlLabel: string;
/** RichTextEditor.ClearFormatting control aria-label */
clearFormattingControlLabel: string;
/** RichTextEditor.Link control aria-label */
linkControlLabel: string;
/** RichTextEditor.Unlink control aria-label */
unlinkControlLabel: string;
/** RichTextEditor.BulletList control aria-label */
bulletListControlLabel: string;
/** RichTextEditor.OrderedList control aria-label */
orderedListControlLabel: string;
/** RichTextEditor.H1 control aria-label */
h1ControlLabel: string;
/** RichTextEditor.H2 control aria-label */
h2ControlLabel: string;
/** RichTextEditor.H3 control aria-label */
h3ControlLabel: string;
/** RichTextEditor.H4 control aria-label */
h4ControlLabel: string;
/** RichTextEditor.H5 control aria-label */
h5ControlLabel: string;
/** RichTextEditor.H6 control aria-label */
h6ControlLabel: string;
/** RichTextEditor.Blockquote control aria-label */
blockquoteControlLabel: string;
/** RichTextEditor.AlignLeft control aria-label */
alignLeftControlLabel: string;
/** RichTextEditor.AlignCenter control aria-label */
alignCenterControlLabel: string;
/** RichTextEditor.AlignRight control aria-label */
alignRightControlLabel: string;
/** RichTextEditor.AlignJustify control aria-label */
alignJustifyControlLabel: string;
/** RichTextEditor.Code control aria-label */
codeControlLabel: string;
/** RichTextEditor.CodeBlock control aria-label */
codeBlockControlLabel: string;
/** RichTextEditor.Subscript control aria-label */
subscriptControlLabel: string;
/** RichTextEditor.Superscript control aria-label */
superscriptControlLabel: string;
/** RichTextEditor.ColorPicker control aria-label */
colorPickerControlLabel: string;
/** RichTextEditor.UnsetColor control aria-label */
unsetColorControlLabel: string;
/** RichTextEditor.Highlight control aria-label */
highlightControlLabel: string;
/** RichTextEditor.Undo control aria-label */
undoControlLabel: string;
/** RichTextEditor.Redo control aria-label */
redoControlLabel: string;
/** A function go get RichTextEditor.Color control aria-label based on color that control applies */
colorControlLabel: (color: string) => string;
/** aria-label for link editor url input */
linkEditorInputLabel: string;
/** placeholder for link editor url input */
linkEditorInputPlaceholder: string;
/** Content of external button tooltip in link editor when the link was chosen to open in a new tab */
linkEditorExternalLink: string;
/** Content of external button tooltip in link editor when the link was chosen to open in the same tab */
linkEditorInternalLink: string;
/** Save button content in link editor */
linkEditorSave: string;
/** Cancel button title text in color picker control */
colorPickerCancel: string;
/** Clear button title text in color picker control */
colorPickerClear: string;
/** Color picker button title text in color picker control */
colorPickerColorPicker: string;
/** Palette button title text in color picker control */
colorPickerPalette: string;
/** Save button title text in color picker control */
colorPickerSave: string;
/** aria-label for color palette colors */
colorPickerColorLabel: (color: string) => string;
}
Default labels (can be imported from @mantine/tiptap package):
import { RichTextEditorLabels } from '@mantine/tiptap';
export const DEFAULT_LABELS: RichTextEditorLabels = {
// Controls labels
linkControlLabel: 'Link',
colorPickerControlLabel: 'Text color',
highlightControlLabel: 'Highlight text',
colorControlLabel: (color) => `Set text color ${color}`,
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: (color) => `Set text color ${color}`,
};