FloatingMenu extension
Use the Floating Menu extension in Tiptap to make a menu appear on an empty line.
If you are using a framework like React or Vue, use the frameworks specific FloatingMenu component instead of the extension. The component provides a more convenient API and handles the DOM element for you. You can find more information about the component in the Usage with frameworks section below.
Install the extension
Install the Floating Menu extension and the Floating UI library.
npm install @tiptap/extension-floating-menu @floating-ui/dom@^1.6.0Settings
element
The DOM element that contains your menu.
Type: HTMLElement
Default: null
updateDelay
The FloatingMenu debounces the update method to allow the floating menu to not be updated on every selection update. This can be controlled in milliseconds.
The FloatingMenuPlugin will come with a default delay of 250ms. This can be deactivated, by setting the delay to 0 which deactivates the debounce.
Type: Number
Default: 250
resizeDelay
The FloatingMenu debounces the resize and scroll event handlers to allow the floating menu to not be updated on every resize or scroll event. This can be controlled in milliseconds.
Type: Number
Default: 60
appendTo
The element to which the floating menu should be appended to in the DOM. Can be a HTMLElement or a callback function that returns a HTMLElement.
Type: HTMLElement | (() => HTMLElement) | undefined
Default: undefined, the menu will be appended to document.body.
options
Under the hood, the FloatingMenu uses Floating UI. You can control the middleware and positioning of the floating menu with these options.
Type: Object
Default: { strategy: 'absolute', placement: 'right' }
| Option | Type | Description |
|---|---|---|
strategy | string | The positioning strategy. See here |
placement | string | The placement of the menu. See here |
offset | number, OffsetOptions or boolean | The offset middleware options. If true use default options, if false disable the middleware |
flip | FlipOptions or boolean | The flip middleware options. If true use default options, if false disable the middleware |
shift | ShiftOptions or boolean | The shift middleware options. If true use default options, if false disable the middleware |
arrow | ArrowOptions or false | The arrow middleware options. If false disable the middleware |
size | SizeOptions or boolean | The size middleware options. If true use default options, if false disable the middleware |
autoPlacement | AutoPlacementOptions or boolean | The autoPlacement middleware options. If true use default options, if false disable the middleware |
hide | HideOptions or boolean | The hide middleware options. If true use default options, if false disable the middleware |
inline | InlineOptions or boolean | The inline middleware options. If true use default options, if false disable the middleware |
onShow | Function or undefined | A callback that is called when the menu is shown. This can be used to add custom logic or styles when the menu is displayed. |
onHide | Function or undefined | A callback that is called when the menu is hidden. This can be used to add custom logic or styles when the menu is hidden. |
onUpdate | Function or undefined | A callback that is called when the menu is updated. This can be used to add custom logic or styles when the menu is updated. |
onDestroy | Function or undefined | A callback that is called when the menu is destroyed. This can be used to add custom logic or styles when the menu is removed. |
pluginKey
The key for the underlying ProseMirror plugin. Make sure to use different keys if you add more than one instance.
Type: string | PluginKey
Default: 'floatingMenu'
shouldShow
A callback to control whether the menu should be shown or not.
Type: (props) => boolean
Source code
packages/extension-floating-menu/
Use in Vanilla JavaScript
import { Editor } from '@tiptap/core'
import FloatingMenu from '@tiptap/extension-floating-menu'
new Editor({
extensions: [
FloatingMenu.configure({
element: document.querySelector('.menu'),
}),
],
})Usage with frameworks
React
The @tiptap/react package comes with a FloatingMenu component you can import from @tiptap/react/menus. It provides the same functionality as the extension but with a React-friendly API. When using this component, you don't need to add the FloatingMenu extension to your editor.
import { FloatingMenu } from '@tiptap/react/menus'
function MyFloatingMenu({ editor }) {
return (
<FloatingMenu editor={editor}>
<button onClick={() => editor.chain().focus().setHeading({ level: 1 }).run()}>
H1
</button>
<button onClick={() => editor.chain().focus().setBulletList().run()}>
List
</button>
</FloatingMenu>
)
}Vue
The @tiptap/vue-3 package comes with a FloatingMenu component you can import from @tiptap/vue-3/menus. It provides the same functionality as the extension but with a Vue-friendly API. When using this component, you don't need to add the FloatingMenu extension to your editor.
<template>
<FloatingMenu :editor="editor">
<button @click="editor.chain().focus().setHeading({ level: 1 }).run()">
H1
</button>
<button @click="editor.chain().focus().setBulletList().run()">
List
</button>
</FloatingMenu>
</template>
<script setup>
import { FloatingMenu } from '@tiptap/vue-3/menus'
// make sure to pass the editor instance as a prop to the FloatingMenu component
const { editor } = defineProps({
editor: {
type: Object,
required: true,
},
})
</script>Note: The same menu is also available in the Vue 2 version of Tiptap, you can import it from @tiptap/vue-2/menus.
Custom logic
Customize the logic for showing the menu with the shouldShow option. For components, shouldShow can be passed as a prop.
FloatingMenu.configure({
shouldShow: ({ editor, view, state, oldState }) => {
// show the floating within any paragraph
return editor.isActive('paragraph')
},
})Multiple menus
Use multiple menus by setting an unique pluginKey.
import { Editor } from '@tiptap/core'
import FloatingMenu from '@tiptap/extension-floating-menu'
new Editor({
extensions: [
FloatingMenu.configure({
pluginKey: 'floatingMenuOne',
element: document.querySelector('.menu-one'),
}),
FloatingMenu.configure({
pluginKey: 'floatingMenuTwo',
element: document.querySelector('.menu-two'),
}),
],
})Alternatively you can pass a ProseMirror PluginKey.
import { Editor } from '@tiptap/core'
import FloatingMenu from '@tiptap/extension-floating-menu'
import { PluginKey } from '@tiptap/pm/state'
new Editor({
extensions: [
FloatingMenu.configure({
pluginKey: new PluginKey('floatingMenuOne'),
element: document.querySelector('.menu-one'),
}),
FloatingMenu.configure({
pluginKey: new PluginKey('floatingMenuOne'),
element: document.querySelector('.menu-two'),
}),
],
})Force update the position of the floating menu
If the floating menu changes size after the initial render, its position will not be adjusted automatically. To fix this, you can force update the position of the floating menu using the updateFloatingMenuPosition command:
editor.commands.updateFloatingMenuPosition()Alternatively, you can emit an 'updatePosition' event via transaction metadata:
editor.commands.setMeta('floatingMenu', 'updatePosition')