Tiptap extension that allows you to add a class to the focused node with configurable focus modes
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
The Focus extension allows you to add CSS classes to focused nodes in a Tiptap editor, providing visual focus indicators that enhance user experience and accessibility. It operates as a ProseMirror plugin that decorates nodes based on cursor position, offering three different focus modes for various use cases.
npm install @tiptap/extensionsimport { Focus, FocusOptions } from "@tiptap/extensions";For CommonJS:
const { Focus, FocusOptions } = require("@tiptap/extensions");Sub-path imports (also supported):
import { Focus, FocusOptions } from "@tiptap/extensions/focus";import { Editor } from "@tiptap/core";
import { Focus } from "@tiptap/extensions";
// Basic usage with default options
const editor = new Editor({
extensions: [
Focus,
// ... other extensions
],
content: "<p>Your content here</p>",
});
// Custom configuration
const editor = new Editor({
extensions: [
Focus.configure({
className: 'is-focused',
mode: 'deepest',
}),
// ... other extensions
],
content: "<p>Your content here</p>",
});The Focus extension integrates with Tiptap's extension system and uses ProseMirror's decoration API to efficiently add CSS classes to DOM elements without re-rendering content. Key components:
Creates a Tiptap extension that adds CSS classes to focused nodes based on cursor position.
import { Extension } from "@tiptap/core";
/**
* Focus extension that adds CSS classes to focused nodes
* Extends Tiptap's base Extension class with FocusOptions configuration
*/
const Focus: Extension<FocusOptions>;Configures the Focus extension with custom options.
/**
* Configure the Focus extension with custom options
* @param options - Configuration options for focus behavior
* @returns Configured Focus extension instance
*/
Focus.configure(options: Partial<FocusOptions>): Extension<FocusOptions>;Marks all nodes in the selection path as focused (default behavior).
// Configuration for 'all' mode
Focus.configure({
mode: 'all',
className: 'has-focus'
})Marks only the deepest (innermost) node in the selection as focused.
// Configuration for 'deepest' mode
Focus.configure({
mode: 'deepest',
className: 'has-focus'
})Marks only the shallowest (outermost) node in the selection as focused.
// Configuration for 'shallowest' mode
Focus.configure({
mode: 'shallowest',
className: 'has-focus'
})/**
* Configuration options for the Focus extension
*/
interface FocusOptions {
/**
* The CSS class name that should be added to the focused node
* @default 'has-focus'
* @example 'is-focused'
*/
className: string;
/**
* The mode by which the focused node is determined
* - 'all': All nodes in the selection path are marked as focused
* - 'deepest': Only the innermost node is marked as focused
* - 'shallowest': Only the outermost node is marked as focused
* @default 'all'
*/
mode: 'all' | 'deepest' | 'shallowest';
}import { Editor } from "@tiptap/core";
import { Focus } from "@tiptap/extensions";
const editor = new Editor({
extensions: [
Focus.configure({
className: 'editor-focused-node'
})
],
content: '<p>Your content here</p>',
});// Only highlight the innermost focused element
const editor = new Editor({
extensions: [
Focus.configure({
mode: 'deepest',
className: 'deeply-focused'
})
],
content: '<p>Your content here</p>',
});// Use ARIA-friendly class names for screen readers
const editor = new Editor({
extensions: [
Focus.configure({
className: 'aria-current-element',
mode: 'deepest'
})
],
content: '<p>Your content here</p>',
});/* Style focused nodes */
.has-focus {
outline: 2px solid #007acc;
outline-offset: 2px;
}
/* Different styles for different focus modes */
.deeply-focused {
background-color: rgba(0, 122, 204, 0.1);
border-radius: 4px;
}
.aria-current-element {
box-shadow: 0 0 0 2px #007acc;
}The Focus extension requires:
@tiptap/core for base Extension class@tiptap/pm/state for Plugin and PluginKey@tiptap/pm/view for Decoration and DecorationSet