@liveblocks/react-tiptap
provides you with a React
plugin that adds collaboration to any Tiptap text editor.
It also adds realtime cursors, document persistence on the cloud, comments, and
mentions. Read our get started guides to
learn more. Use
@liveblocks/node-prosemirror
for server-side editing.
To set up your collaborative Tiptap editor, add
useLiveblocksExtension
to your editor, passing the
return value useEditor
extension array.
Liveblocks Tiptap components should be passed editor
to enable them.
Learn more in our get started guides.
Displays a toolbar, allowing you to change the styles of selected text. You can add content before or after, or the toolbar’s options can be customized. A floating toolbar also exists.
Pass your Tiptap editor
to use the component. By default, one of the toolbar
buttons can create comment threads—to enable this add FloatingComposer
and
display threads with AnchoredThreads
or FloatingThreads
.
You can insert content before
the first button and after
the last button
using before
and after
. Components such as Toolbar.Button
and
Toolbar.Toggle
can be used to create new buttons.
For more complex customization, instead read creating a custom floating toolbar.
By passing elements as children, it’s possible to create a fully custom toolbar.
Each part of our default toolbar is available as blocks which can be slotted together. This is how the default toolbar is constructed:
You can mix these default components with any custom ones of your own. Below the
Toolbar.SectionHistory
component is added alongside some custom buttons
created with Toolbar.Button
, Toolbar.Toggle
, and Icon
. The
highlight toggle button requires a
Tiptap extension.
To learn more about the different components, read more below.
The Tiptap editor.
The content of the toolbar, overriding the default content. Use the before
and after
props if you want to keep and extend the default content. Any
ReactNode
or Toolbar.*
components work inside.
The content to display at the start of the toolbar. Any ReactNode
or
Toolbar.*
components work inside.
The content to display at the end of the toolbar. Any ReactNode
or
Toolbar.*
components work inside.
A button for triggering actions. The name
is displayed in a tooltip. Props
such as onClick
will be passed to the underlying button
element.
Optionally takes an icon which will visually replace the name
. Also optionally
accepts a shortcut, which is displayed in the tooltip. Comment key names are
converted to symbols. Here are various examples.
The name of this button displayed in its tooltip. Will also be displayed in
the button if no icon
or children
are passed.
An optional icon displayed in this button.
An optional keyboard shortcut displayed in this button’s tooltip. Common
shortcuts such will be replaced by their symbols, for example CMD
→ ⌘
.
A toggle button for values that can be active or inactive. Best used with text
editor commands. The name
is displayed in a tooltip. Props will be passed to
the underlying button
element.
The snippet above shows how to use the Toggle with the
Tiptap highlight extension.
The toggle button can also be toggled with useState
.
Toolbar.Toggle
optionally takes an icon which will visually replace the
name
. Also optionally accepts a shortcut, which is displayed in the tooltip.
Comment key names are converted to symbols. Here are various examples.
The name of this button displayed in its tooltip. Will also be displayed in
the button if no icon
or children
are passed.
Whether the button is toggled.
An optional icon displayed in this button.
An optional keyboard shortcut displayed in this button’s tooltip. Common
shortcuts such will be replaced by their symbols, for example CMD
→ ⌘
.
Adds a dropdown selector for switching between different block types, such as
text, heading 1, blockquote. Props will be passed to the inner button
element. Can also be placed inside FloatingToolbar
.
If you’d like to change the items shown in the dropdown menu, you can pass a
custom items
array. Below a code block item
(Tiptap extension)
is added after the default options.
By passing a label
property, you can overwrite the styles of the dropdown
items. The toolbar button will still display the name
, but in the dropdown,
the label
will be used instead of the name
and icon
. Below, a new item is
added and its label
is customized.
You can also customize the default items. Below each item is styled to represent the effect each block applies to the document.
The items displayed in this block selector. When provided as an array, the default items are overridden. To avoid this, a function can be provided instead and it will receive the default items.
Adds a visual, and accessible, separator used to separate sections in the
toolbar. Props will be passed to the inner div
element. Can also be placed
inside FloatingToolbar
.
Adds a section containing undo and redo buttons. Can also be placed inside
FloatingToolbar
.
Adds a section containing inline formatting actions such as bold, italic,
underline. Can also be placed inside FloatingToolbar
.
Adds a section containing an add comment button. Can also be placed inside
FloatingToolbar
.
Displays a floating toolbar near the current Tiptap selection, allowing you to change styles. You can add content before or after, or the toolbar’s options can be customized. A static toolbar also exists.
Pass your Tiptap editor
to use the component. By default, one of the toolbar
buttons can create comment threads—to enable this add FloatingComposer
and
display threads with AnchoredThreads
or FloatingThreads
.
Using position
and offset
you can reposition the toolbar relative to the
current selection. position
can be set to "top"
or "bottom"
, and offset
defines the vertical distance in pixels from the selection.
You can insert custom content before
the first button and after
the last
button using before
and after
. Components such as Toolbar.Button
and
Toolbar.Toggle
can be used to create new buttons.
For more complex customization, instead read creating a custom floating toolbar.
By passing elements as children, it’s possible to create a fully custom floating toolbar.
Each part of our default toolbar is available as blocks which can be slotted together. This is how the default floating toolbar is constructed:
You can mix these default components with any custom ones of your own. Below the
Toolbar.SectionHistory
component is added alongside some custom buttons
created with Toolbar.Button
, Toolbar.Toggle
, and Icon
. The
highlight toggle button requires a
Tiptap extension.
To learn more about the different components, read more under Toolbar
.
The Tiptap editor.
The vertical position of the floating toolbar.
The vertical offset of the floating toolbar from the selection.
The content of the toolbar, overriding the default content. Use the before
and after
props if you want to keep and extend the default content. Any
ReactNode
or Toolbar.*
components work inside.
The content to display at the start of the toolbar. Any ReactNode
or
Toolbar.*
components work inside.
The content to display at the end of the toolbar. Any ReactNode
or
Toolbar.*
components work inside.
Displays a Composer
near the current Tiptap selection, allowing you to
create threads.
Submitting a comment will attach an annotation thread at the current selection.
Should be passed your Tiptap editor
, and it’s recommended you set a width
value. Display created threads with AnchoredThreads
or
FloatingThreads
.
To open the FloatingComposer
, you need to click the “Comment” button in the
Toolbar
or call the addPendingComment
command added by Liveblocks. You
can use liveblocksCommentMark
to check if the current selection is a comment.
The metadata of the thread to create.
The event handler called when the composer is submitted.
The composer’s initial value.
Whether the composer is collapsed. Setting a value will make the composer controlled.
The event handler called when the collapsed state of the composer changes.
Whether the composer is initially collapsed. Setting a value will make the composer uncontrolled.
Whether the composer is disabled.
Whether to focus the composer on mount.
Override the component’s strings.
Displays floating Thread
components below text highlights in the editor.
Takes a list of threads retrieved from useThreads
and renders them to the
page. Each thread is opened by clicking on its corresponding text highlight.
Should be passed your Tiptap editor
, and it’s recommended you set a width
value.
FloatingThreads
and AnchoredThreads
have been designed to work
together to provide the optimal experience on mobile and desktop. We generally
recommend using both components, hiding one on smaller screens, as we are below
with Tailwind classes. Most apps also don’t need to display resolved threads, so
we can filter those out with a useThreads
option.
We can place this component inside ClientSideSuspense
to prevent it
rendering until threads have loaded.
The FloatingThreads
component acts as a wrapper around each individual
Thread
. You can treat the component like you would a div
, using classes,
listeners, and more.
To apply styling to each Thread
, you can pass a custom Thread
property
to components
and modify this in any way. This is the best way to modify a
thread’s width.
You can return any custom ReactNode
here, including anything from a simple
wrapper around Thread
, up to a full custom Thread
component built using our
Comment primitives.
The threads to display.
Override the component’s components.
Override the Thread
component.
Displays a list of Thread
components vertically alongside the editor.
Takes a list of threads retrieved from useThreads
and renders them to the
page. Each thread is displayed at the same vertical coordinates as its
corresponding text highlight. If multiple highlights are in the same location,
each thread is placed in order below the previous thread.
FloatingThreads
and AnchoredThreads
have been designed to work
together to provide the optimal experience on mobile and desktop. We generally
recommend using both components, hiding one on smaller screens, as we are below
with Tailwind classes. Most apps also don’t need to display resolved threads, so
we can filter those out with a useThreads
option.
We can place this component inside ClientSideSuspense
to prevent it
rendering until threads have loaded.
The AnchoredThreads
component acts as a wrapper around each Thread
. It
has no width, so setting this is required, and each thread will take on the
width of the wrapper. You can treat the component like you would a div
, using
classes, listeners, and more.
To apply styling to each Thread
, you can pass a custom Thread
property
to components
and modify this in any way.
You can return any custom ReactNode
here, including anything from a simple
wrapper around Thread
, up to a full custom Thread
component built using our
Comment primitives.
Using CSS variables you can modify the gap between threads, and the horizontal offset that’s added when a thread is selected.
The threads to display.
Override the component’s components.
Override the Thread
component.
The HistoryVersionPreview
component allows you to display a preview of a
specific version of your Tiptap editor’s content. It also contains a button and
logic for restoring. It must be used inside the <LiveblocksPlugin>
context. To
render a list of versions, see
VersionHistory
.
The version of the editor content to preview.
Callback function called when the user chooses to restore this version.
The HistoryVersionPreview
component renders a read-only view of the specified
version of the editor content. It also provides a button for users to restore
the displayed version.
Displays a floating AI toolbar near the current Tiptap selection, allowing you to use AI to apply changes to the document or ask questions about it.
Pass your Tiptap editor
to use the component, and enable (or customize) the AI
option in useLiveblocksExtension
.
To open the AiToolbar
, you need to call the askAi
command added by Liveblocks.
You can also pass a prompt to the askAi
command and it will directly request
it when opening the toolbar.
By default, the AI toolbar displays a list of suggestions (e.g. “Fix mistakes”,
“Explain”, etc). These can be customized via the suggestions
prop and the
AiToolbar.Suggestion
component.
Doing so will override the default suggestions, instead you can use a function to keep them while adding your own.
The Tiptap editor.
The vertical offset of the AI toolbar from the selection.
The prompt suggestions to display below the AI toolbar.
A prompt suggestion displayed below the AI toolbar.
By default, selecting a suggestion will use its label from the children
as the
prompt, this can be overridden with the prompt
prop. Also optionally takes an
icon.
The suggestion’s label, used as the prompt if the prompt
prop is not set.
An optional icon displayed before the label.
The prompt to use instead of the label.
A label to describe a group of prompt suggestions displayed in the AI toolbar.
A separator between groups of prompt suggestions displayed in the AI toolbar.
Liveblocks plugin for Tiptap that adds collaboration to your editor.
liveblocks
should be passed to Tiptap’s useEditor
as an extension.
A number of options can be applied.
Returns a Liveblocks Tiptap extension.
The initial content for the editor, if it’s never been set. Learn more.
The name of this text editor’s field. Allows you to use multiple editors on one page, if each has a separate field value. Learn more.
Experimental. Enable offline support using IndexedDB. This means the after the first load, documents will be stored locally and load instantly. Learn more.
Enable comments in the editor.
Enable mentions in the editor.
Enable AI in the editor and optionally customize configuration options.
Initial content for the editor can be set with initialContent
. This content
will only be used if the current editor has never been edited by any users, and
is ignored otherwise.
It’s possible to use multiple editors on one page by passing values to the
field
property. Think of it like an ID for the current editor.
Here’s an example of how multiple editors may be set up.
It’s possible to enable offline support in your editor with an experimental
option. This means that once a document has been opened, it’s saved locally on
the browser, and can be shown instantly without a loading screen. As soon as
Liveblocks connects, any remote changes will be synchronized, without any load
spinner. Enable this by passing a offlineSupport_experimental
value.
To make sure that your editor loads instantly, you must structure your app
carefully to avoid any Liveblocks hooks and ClientSideSuspense
components
from triggering a loading screen. For example, if you’re displaying threads in
your editor with useThreads
, you must place this inside a separate
component and wrap it in ClientSideSuspense
.
By default, AI components like AiToolbar
use the term "AI"
. This can be
customized with the ai.name
option in useLiveblocksExtension
. This value
will be used throughout the AI components: "Ask {name}"
in the Toolbar
/
FloatingToolbar
default buttons, "{name} is thinking…"
in the
AiToolbar
, etc.
If you’re after visual customization, AI components like AiToolbar
integrate with the rest of Liveblocks' styles, heavily using tokens like
--lb-accent
for example. Learn more about styling.
By default, the AiToolbar
component sends its requests to Liveblocks to
generate its responses. This can be customized via the
ai.resolveContextualPrompt
option in useLiveblocksExtension
. This option
accepts an async function which will be called by the AI toolbar whenever a
prompt is requested, it will receive the prompt and some context (the document’s
and selection’s text, the previous request if it’s a follow-up, etc) and is
expected to return the type of response and the text to use.
Used to check if the editor content has been loaded or not, helpful for displaying a loading skeleton.
Here’s how it can be used in the context of your editor.
React Tiptap comes with default styles, and these can be imported into the root
of your app or directly into a CSS file with @import
. Note that you must also
install and import a stylesheet from
@liveblocks/react-ui
to use these
styles.
Adding dark mode and customizing your styles is part of @liveblocks/react-ui
,
learn how to do this under
styling and customization.
We use cookies to collect data to improve your experience on our site. Read our Privacy Policy to learn more.