Move Node Button
A fully accessible move node button for Tiptap editors. Reorder selected nodes or blocks in the editor with keyboard shortcut support and smart selection handling.
Installation
Add the component via the Tiptap CLI:
npx @tiptap/cli@latest add move-node-buttonComponents
<MoveNodeButton />
A prebuilt React component that moves nodes up or down in the editor.
Usage
import { MoveNodeButton } from '@/components/tiptap-ui/move-node-button'
import { useEditor } from '@tiptap/react'
export default function MyEditor() {
const editor = useEditor({
// your editor configuration
})
return (
<>
<MoveNodeButton
editor={editor}
direction="up"
text="Move Up"
hideWhenUnavailable={true}
showShortcut={true}
onMoved={(direction) => console.log(`Node moved ${direction}!`)}
/>
<MoveNodeButton
editor={editor}
direction="down"
text="Move Down"
hideWhenUnavailable={true}
showShortcut={true}
onMoved={(direction) => console.log(`Node moved ${direction}!`)}
/>
</>
)
}Props
| Name | Type | Default | Description |
|---|---|---|---|
editor | Editor | null | undefined | The Tiptap editor instance |
direction | "up" | "down" | Required | Direction to move the node |
text | string | undefined | Optional text label for the button |
hideWhenUnavailable | boolean | false | Hides the button when moving is not available |
onMoved | (direction: "up" | "down") => void | undefined | Callback fired after a successful move |
showShortcut | boolean | false | Shows a keyboard shortcut badge (if available) |
Hooks
useMoveNode()
A custom hook to build your own move node button with full control over rendering and behavior.
Usage
import { useMoveNode } from '@/components/tiptap-ui/move-node-button'
import { parseShortcutKeys } from '@/lib/tiptap-utils'
import { Badge } from '@/components/ui/badge'
import { useEditor } from '@tiptap/react'
function MyMoveNodeButton({ direction }: { direction: 'up' | 'down' }) {
const editor = useEditor({
// your editor configuration
})
const { isVisible, handleMoveNode, canMoveNode, label, shortcutKeys, Icon } = useMoveNode({
editor,
direction,
hideWhenUnavailable: true,
onMoved: (direction) => console.log(`Node moved ${direction}!`),
})
if (!isVisible) return null
return (
<button onClick={handleMoveNode} disabled={!canMoveNode} aria-label={label}>
<Icon />
{label}
{shortcutKeys && <Badge>{parseShortcutKeys({ shortcutKeys })}</Badge>}
</button>
)
}Props
| Name | Type | Default | Description |
|---|---|---|---|
editor | Editor | null | undefined | The Tiptap editor instance |
direction | "up" | "down" | Required | Direction to move the node |
hideWhenUnavailable | boolean | false | Hides the button if moving cannot be performed |
onMoved | (direction: "up" | "down") => void | undefined | Callback fired after successful move |
Return Values
| Name | Type | Description |
|---|---|---|
isVisible | boolean | Whether the button should be rendered |
canMoveNode | boolean | If a node can be moved in the specified direction |
handleMoveNode | () => boolean | Function to move the selected node |
label | string | Accessible label text for the button |
shortcutKeys | string | Keyboard shortcut for the direction |
Icon | React.FC | Icon component for the move button (AlignTopIcon/AlignBottomIcon) |
Utilities
canMoveNode(editor, direction)
Checks if a node can be moved in the specified direction in the current editor state.
Parameters
editor(Editor | null) - The Tiptap editor instancedirection("up" | "down") - The direction to check
Returns
boolean - True if the node can be moved in the specified direction, false otherwise
Usage
import { canMoveNode } from '@/components/tiptap-ui/move-node-button'
import type { Editor } from '@tiptap/react'
const canMoveUp = canMoveNode(editor, 'up')
const canMoveDown = canMoveNode(editor, 'down')moveNode(editor, direction)
Programmatically moves the selected node or block in the specified direction.
Parameters
editor(Editor | null) - The Tiptap editor instancedirection("up" | "down") - The direction to move the node
Returns
boolean - True if the move was successful, false otherwise
Usage
import { moveNode } from '@/components/tiptap-ui/move-node-button'
import type { Editor } from '@tiptap/react'
const success = moveNode(editor, 'up')
if (success) {
console.log('Node moved successfully!')
}shouldShowButton(props)
Determines if the move button should be visible based on editor state and configuration.
Parameters
props- Configuration objecteditor(Editor | null) - The Tiptap editor instancedirection("up" | "down") - The direction to checkhideWhenUnavailable(boolean) - Whether to hide when moving is unavailable
Returns
boolean - True if the button should be shown, false otherwise
Usage
import { shouldShowButton } from '@/components/tiptap-ui/move-node-button'
import type { Editor } from '@tiptap/react'
const shouldShow = shouldShowButton({
editor,
direction: 'up',
hideWhenUnavailable: true,
})Keyboard Shortcuts
The move node button supports the following keyboard shortcuts:
- Cmd/Ctrl + Shift + Arrow Up: Move the selected node up
- Cmd/Ctrl + Shift + Arrow Down: Move the selected node down
The shortcuts are automatically registered when using either the <MoveNodeButton /> component or the useMoveNode() hook. These shortcuts work with any block-level node including paragraphs, headings, blockquotes, and code blocks.
Requirements
Dependencies
@tiptap/react- Core Tiptap React integration@tiptap/pm/state- ProseMirror state managementreact-hotkeys-hook- Keyboard shortcut management
Referenced Components
use-tiptap-editor(hook)use-mobile(hook)button(primitive)badge(primitive)tiptap-utils(lib)tiptap-advanced-utils(lib)align-top-icon(icon)align-bottom-icon(icon)