tiptap-utility
v3.0.1
Published
List of utils functions, helps to build custom extension and help working with tiptap editor
Maintainers
Readme
Tiptap Utility Package
A collection of utility functions to enhance your workflow with the Tiptap editor.
Installation
npm install tiptap-utilityUtilities
Quick Access
- isTextSelected
- getWordCount
- getFocusedNodeContainer
- getAllNodesOfType
- getAllNodesByTypeAndAttrs
- getAllMarksByTypeAndAttrs
- findParentNodeOfTypeAtPosition
- getEditorState
- getNodesInRange
- getLastChildNode
- getNextSiblingNode
- mapEachNode
- filterEachNode
isTextSelected
Checks if text is selected in the Tiptap editor.
Parameters:
editor: TiptapEditorinstance.
Returns:
boolean:trueif text is selected and editor is editable, otherwisefalse.
Example:
import { isTextSelected } from 'tiptap-utility';
const isSelected = isTextSelected({ editor });
console.log(isSelected ? "Text is selected" : "No text selected");getWordCount
Counts the number of words in the Tiptap editor content.
Parameters:
editor: TiptapEditorinstance.
Returns:
number: Total word count.
Example:
import { getWordCount } from 'tiptap-utility';
const wordCount = getWordCount(editor);
console.log(`Word count: ${wordCount}`);getFocusedNodeContainer
Finds the focused node container in the Tiptap editor DOM based on the specified nodeType.
Parameters:
editor: TiptapEditorinstance.nodeType: The target node type to locate.attribute(optional): Attribute used to identify the node. Default is'data-type'.focusClass(optional): CSS class used to identify focused nodes. Default is'has-focus'.
Returns:
HTMLElement | null: The focused node container ornullif not found.
Example:
import { getFocusedNodeContainer } from 'tiptap-utility';
const container = getFocusedNodeContainer(editor, 'paragraph');
if (container) {
console.log('Focused node container:', container);
} else {
console.log('No focused container found.');
}getAllNodesOfType
Retrieves all nodes of a specified type from the Tiptap editor document, including those nested within lists, tables, or other container nodes.
Parameters:
editor: TiptapEditorinstance.type: The target node type to locate (e.g.,'heading','paragraph').
Returns:
Array<{ node: Node, pos: number }>:- An array of objects where each object contains:
node: The node instance of the specified type.pos: The position of the node in the document.
- An array of objects where each object contains:
Example:
import { getAllNodesOfType } from 'tiptap-utility';
const headings = getAllNodesOfType(editor, 'heading');
headings.forEach(({ node, pos }) => {
console.log('Found heading:', node, 'at position:', pos);
});getAllNodesByTypeAndAttrs
Finds all nodes of a given type and with specific attributes in the Tiptap editor's document.
Parameters:
editor: TiptapEditorinstance.type: A string representing the type of node to search for.attrs: An object containing the attributes to match against the nodes.
Returns:
Array<{ node: any; pos: number }>: An array of nodes and their positions that match the given type and attributes.
Example:
import { getAllNodesByTypeAndAttrs } from 'tiptap-utility';
const nodes = getAllNodesByTypeAndAttrs({ editor }, 'image', { src: 'https://example.com/image.jpg' });
console.log(nodes);getAllMarksByTypeAndAttrs
Finds all marks of a given type and with specific attributes in the Tiptap editor's document.
Parameters:
editor: TiptapEditorinstance.markTypeName: A string representing the type of mark to search for (e.g.,'bold','italic','link').attrs: An object containing the attributes to match against the marks.match(optional): The matching strategy -'and'(default) requires all attributes to match,'or'requires at least one attribute to match.
Returns:
Array<{ from: number; to: number; attrs: any }>: An array of objects where each object contains:from: The starting position of the marked text.to: The ending position of the marked text.attrs: The attributes of the mark.
Example:
import { getAllMarksByTypeAndAttrs } from 'tiptap-utility';
// Find all bold marks
const boldMarks = getAllMarksByTypeAndAttrs(editor, 'bold', {});
console.log(boldMarks);
// Find all link marks with specific href
const linkMarks = getAllMarksByTypeAndAttrs(editor, 'link', { href: 'https://example.com' });
console.log(linkMarks);
// Find marks where any of the specified attributes match (using 'or' strategy)
const colorMarks = getAllMarksByTypeAndAttrs(editor, 'textStyle', { color: '#ff0000' }, 'or');
console.log(colorMarks);findParentNodeOfTypeAtPosition
Finds the parent node of a given type at a specific position in the Tiptap editor.
Parameters:
editor: TiptapEditorinstance.position: The position in the document where the search for the parent node begins.parentNodeTypeName: The name of the parent node type to search for.
Returns:
{ node: any; depth: number; start: number; end: number } | null: An object containing the parent node, its depth, and its start and end positions if found, otherwisenull.
Example:
import { findParentNodeOfTypeAtPosition } from 'tiptap-utility';
const parentNode = findParentNodeOfTypeAtPosition({ editor }, 10, 'paragraph');
if (parentNode) {
console.log('Parent node found:', parentNode);
} else {
console.log('No parent node found at the specified position');
}getEditorState
Retrieves the current state of the Tiptap editor.
Parameters:
editor: TiptapEditorinstance.
Returns:
object: The current state of the editor, either fromeditor.stateoreditor.view.state.
Example:
import { getEditorState } from 'tiptap-utility';
const editorState = getEditorState({ editor });
console.log(editorState);getNodesInRange
Extracts all nodes within a specified range in the Tiptap editor document. Optionally, it can filter nodes by specified types.
Parameters
editor(required): An instance of the TiptapEditor.from(required): The starting position of the range (inclusive).to(required): The ending position of the range (exclusive).nodeType(optional): An array of node type names to filter for, ornullto include all node types. Defaults tonull.
Returns
NodeWithPosition[]: An array of objects, where each object contains:node: The ProseMirrorNodeinstance.pos: The starting position of the node within the document.
Example
import { getNodesInRange } from 'tiptap-utility';
const from = 0;
const to = 50;
const nodeTypes = ['paragraph', 'heading'];
const nodes = getNodesInRange(editor, from, to, nodeTypes);
nodes.forEach(({ node, pos }) => {
console.log(`Node of type ${node.type.name} found at position ${pos}`);
});getLastChildNode
Retrieves the last child node of a given node along with its starting position.
Parameters
node(required): A ProseMirrorNodefrom which to find the last child.
Returns
{ node: Node, pos: number } | null:- If the node has child nodes, returns an object containing:
node: The last childNode.pos: The starting position of the last child node.
- Returns
nullif the node has no children.
- If the node has child nodes, returns an object containing:
Example
import { getLastChildNode } from 'tiptap-utility';
const parentNode = editor.state.doc.nodeAt(0); // Example parent node
if (parentNode) {
const lastChild = getLastChildNode(parentNode);
if (lastChild) {
console.log(`Last child node type: ${lastChild.node.type.name}`);
console.log(`Position: ${lastChild.pos}`);
} else {
console.log('No child nodes found.');
}
}getNextSiblingNode
Finds the next sibling node of a given node within its parent.
Parameters
parent(required): A ProseMirrorNoderepresenting the parent container.currentNode(required): The child node whose next sibling needs to be found.
Returns
{ node: Node } | null:- If a next sibling exists, returns an object containing:
node: The next siblingNode.
- Returns
nullif there is no next sibling.
- If a next sibling exists, returns an object containing:
Example
import { getNextSiblingNode } from 'tiptap-utility';
const parentNode = editor.state.doc.nodeAt(0); // Example parent node
const currentNode = parentNode?.firstChild; // Example current node
if (parentNode && currentNode) {
const nextSibling = getNextSiblingNode(parentNode, currentNode);
if (nextSibling) {
console.log(`Next sibling node type: ${nextSibling.node.type.name}`);
} else {
console.log('No next sibling found.');
}
}mapEachNode
Recursively traverses a Tiptap JSONContent node tree and applies a callback to each node. Useful for transforming or inspecting every node in a document (e.g. changing node types, stripping marks, or collecting stats). The tree is traversed in place; the callback can return a modified or replaced node.
Parameters
node(required): A TiptapJSONContentobject (e.g. fromeditor.getJSON()or a single node).callback(required): A function(node: JSONContent) => JSONContentcalled for each node that has atypeproperty. Return the same or a modified node; that value is used for that node in the tree.
Returns
JSONContent: The root node after applying the callback to it and recursively to all descendants. The original structure is mutated.
Example
import { mapEachNode } from 'tiptap-utility';
const json = editor.getJSON();
// Example: ensure every paragraph has an empty attrs object
const normalized = mapEachNode(json, (node) => {
if (node.type === 'paragraph' && !node.attrs) {
return { ...node, attrs: {} };
}
return node;
});
// Example: collect all node types (inspect only)
const types: string[] = [];
mapEachNode(json, (node) => {
if (node.type) types.push(node.type);
return node;
});
console.log('Node types in document:', types);filterEachNode
Recursively traverses a Tiptap JSONContent node tree and returns a new tree containing only nodes that pass a predicate. Does not mutate the input. Useful for stripping certain node types (e.g. images, embeds) or building a reduced copy of the document.
Parameters
node(required): A TiptapJSONContentobject (e.g. fromeditor.getJSON()or a single node).predicate(required): A function(node: JSONContent) => booleancalled for each node that has atypeproperty. Returntrueto keep the node (and its filtered subtree),falseto remove it.
Returns
JSONContent | null: A new tree with only nodes for which the predicate returnedtrue. Returnsnullif the root node is filtered out. The original structure is not mutated.
Example
import { filterEachNode } from 'tiptap-utility';
const json = editor.getJSON();
// Remove all image nodes from the document
const withoutImages = filterEachNode(json, (node) => node.type !== 'image');
// Keep only block-level nodes (e.g. for a plain-text outline)
const blocksOnly = filterEachNode(json, (node) =>
['paragraph', 'heading', 'blockquote', 'listItem'].includes(node.type ?? '')
);License
This package is open-source and available under the MIT License.
