0
# @tiptap/core
1
2
@tiptap/core is a headless rich text editor built on top of ProseMirror. It provides a flexible, extensible architecture for building custom rich text editors with nodes, marks, extensions, and commands. The library is framework-agnostic and can be integrated with React, Vue, Svelte, or used in vanilla JavaScript/TypeScript applications.
3
4
## Package Information
5
6
- **Package Name**: @tiptap/core
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install @tiptap/core @tiptap/pm`
10
- **Peer Dependencies**: @tiptap/pm (ProseMirror packages wrapper)
11
12
## Core Imports
13
14
```typescript
15
import { Editor, Extension, Node, Mark } from '@tiptap/core';
16
```
17
18
For CommonJS:
19
20
```javascript
21
const { Editor, Extension, Node, Mark } = require('@tiptap/core');
22
```
23
24
JSX Runtime (optional):
25
26
```typescript
27
import { createElement, Fragment, h } from '@tiptap/core';
28
```
29
30
## Basic Usage
31
32
```typescript
33
import { Editor, Extension } from '@tiptap/core';
34
35
// Create a basic extension
36
const BasicExtension = Extension.create({
37
name: 'basicExtension',
38
39
addCommands() {
40
return {
41
insertText: (text: string) => ({ commands }) => {
42
return commands.insertContent(text);
43
}
44
};
45
}
46
});
47
48
// Create and mount editor
49
const editor = new Editor({
50
element: document.querySelector('#editor'),
51
content: '<p>Hello World!</p>',
52
extensions: [BasicExtension],
53
onUpdate: ({ editor }) => {
54
console.log('Content updated:', editor.getHTML());
55
}
56
});
57
58
// Use commands
59
editor.commands.insertText('Hello Tiptap!');
60
61
// Chain commands
62
editor
63
.chain()
64
.focus()
65
.insertContent('More content')
66
.run();
67
68
// Check if commands can be executed
69
if (editor.can().insertContent('test')) {
70
editor.commands.insertContent('test');
71
}
72
```
73
74
## Architecture
75
76
@tiptap/core is built around several key components:
77
78
- **Editor**: The central editor instance that manages state, view, extensions, and commands
79
- **Extensions**: Modular functionality that can be added to the editor (non-content features)
80
- **Nodes**: Document content structures (paragraphs, headings, lists, etc.)
81
- **Marks**: Text formatting (bold, italic, links, etc.)
82
- **Commands**: Actions that can be performed on the editor
83
- **Rules**: Input and paste transformation rules for shortcuts and content processing
84
- **Views**: Custom DOM representations for nodes and marks
85
- **Helpers**: Utility functions for document manipulation and querying
86
87
## Capabilities
88
89
### Editor Core
90
91
Central editor class that manages the editor state, extensions, and provides the main API interface.
92
93
```typescript { .api }
94
class Editor {
95
constructor(options: Partial<EditorOptions>);
96
97
// Core properties
98
view: EditorView;
99
state: EditorState;
100
schema: Schema;
101
storage: Storage;
102
isEditable: boolean;
103
isFocused: boolean;
104
isEmpty: boolean;
105
isDestroyed: boolean;
106
isInitialized: boolean;
107
108
// Lifecycle methods
109
mount(element?: Element): Editor;
110
unmount(): Editor;
111
destroy(): void;
112
113
// Command execution
114
commands: SingleCommands;
115
chain(): ChainedCommands;
116
can(): CanCommands;
117
118
// Content methods
119
getHTML(): string;
120
getJSON(): JSONContent;
121
getText(options?: GetTextOptions): string;
122
setOptions(options: Partial<EditorOptions>): void;
123
setEditable(editable: boolean): void;
124
125
// State inspection
126
getAttributes(nameOrType: string | NodeType | MarkType): Record<string, any>;
127
isActive(name: string, attributes?: Record<string, any>): boolean;
128
129
// Content querying
130
$pos(pos: number): NodePos;
131
$node(selector: string, attributes?: Record<string, any>): NodePos | null;
132
$nodes(selector: string, attributes?: Record<string, any>): NodePos[];
133
134
// Plugin management
135
registerPlugin(plugin: Plugin, handlePlugins?: (newPlugin: Plugin, plugins: Plugin[]) => Plugin[]): EditorState;
136
unregisterPlugin(nameOrPluginKey: string | PluginKey | (string | PluginKey)[]): EditorState | undefined;
137
}
138
139
interface EditorOptions {
140
element?: Element;
141
content?: Content;
142
extensions?: Extensions;
143
injectCSS?: boolean;
144
injectNonce?: string;
145
autofocus?: FocusPosition;
146
editable?: boolean;
147
editorProps?: EditorProps;
148
parseOptions?: ParseOptions;
149
enableInputRules?: boolean;
150
enablePasteRules?: boolean;
151
enableCoreExtensions?: boolean | Record<string, boolean>;
152
enableContentCheck?: boolean;
153
emitContentError?: boolean;
154
coreExtensionOptions?: {
155
clipboardTextSerializer?: {
156
blockSeparator?: string;
157
};
158
delete?: {
159
asyncDeleteEvents?: boolean;
160
};
161
};
162
onBeforeCreate?(props: EditorEvents['beforeCreate']): void;
163
onCreate?(props: EditorEvents['create']): void;
164
onMount?(props: EditorEvents['mount']): void;
165
onUnmount?(props: EditorEvents['unmount']): void;
166
onUpdate?(props: EditorEvents['update']): void;
167
onSelectionUpdate?(props: EditorEvents['selectionUpdate']): void;
168
onTransaction?(props: EditorEvents['transaction']): void;
169
onFocus?(props: EditorEvents['focus']): void;
170
onBlur?(props: EditorEvents['blur']): void;
171
onContentError?(props: EditorEvents['contentError']): void;
172
onDestroy?(): void;
173
}
174
```
175
176
[Editor Core](./editor-core.md)
177
178
### Extension System
179
180
Flexible extension system for adding functionality to the editor through Extensions, Nodes, and Marks.
181
182
```typescript { .api }
183
class Extension<Options = any, Storage = any> {
184
static create<O = any, S = any>(config?: Partial<ExtensionConfig<O, S>>): Extension<O, S>;
185
186
configure(options?: Partial<Options>): Extension<Options, Storage>;
187
extend<ExtendedOptions = Options, ExtendedStorage = Storage>(
188
extendedConfig?: Partial<ExtensionConfig<ExtendedOptions, ExtendedStorage>>
189
): Extension<ExtendedOptions, ExtendedStorage>;
190
}
191
192
class Node<Options = any, Storage = any> {
193
static create<O = any, S = any>(config?: Partial<NodeConfig<O, S>>): Node<O, S>;
194
195
configure(options?: Partial<Options>): Node<Options, Storage>;
196
extend<ExtendedOptions = Options, ExtendedStorage = Storage>(
197
extendedConfig?: Partial<NodeConfig<ExtendedOptions, ExtendedStorage>>
198
): Node<ExtendedOptions, ExtendedStorage>;
199
}
200
201
class Mark<Options = any, Storage = any> {
202
static create<O = any, S = any>(config?: Partial<MarkConfig<O, S>>): Mark<O, S>;
203
204
configure(options?: Partial<Options>): Mark<Options, Storage>;
205
extend<ExtendedOptions = Options, ExtendedStorage = Storage>(
206
extendedConfig?: Partial<MarkConfig<ExtendedOptions, ExtendedStorage>>
207
): Mark<ExtendedOptions, ExtendedStorage>;
208
209
static handleExit(options: { editor: Editor; mark: ProseMirrorMark }): boolean;
210
}
211
```
212
213
[Extension System](./extension-system.md)
214
215
### Command System
216
217
Powerful command system for executing, chaining, and validating editor actions.
218
219
```typescript { .api }
220
interface SingleCommands {
221
[key: string]: (attributes?: Record<string, any>) => boolean;
222
}
223
224
interface ChainedCommands {
225
[key: string]: (attributes?: Record<string, any>) => ChainedCommands;
226
run(): boolean;
227
}
228
229
interface CanCommands {
230
[key: string]: (attributes?: Record<string, any>) => boolean;
231
}
232
233
class CommandManager {
234
constructor(props: { editor: Editor; state: EditorState });
235
236
readonly commands: SingleCommands;
237
chain(): ChainedCommands;
238
can(): CanCommands;
239
createChain(startTr?: Transaction, shouldDispatch?: boolean): ChainedCommands;
240
createCan(startTr?: Transaction): CanCommands;
241
}
242
243
interface CommandProps {
244
editor: Editor;
245
tr: Transaction;
246
commands: SingleCommands;
247
can: CanCommands;
248
chain: () => ChainedCommands;
249
state: EditorState;
250
view: EditorView;
251
dispatch: ((tr: Transaction) => void) | undefined;
252
}
253
```
254
255
[Command System](./command-system.md)
256
257
### Document Helpers
258
259
Comprehensive set of helper functions for document manipulation, content generation, and state inspection.
260
261
```typescript { .api }
262
// Content generation
263
function generateHTML(doc: JSONContent, extensions: Extensions): string;
264
function generateJSON(content: string, extensions: Extensions): JSONContent;
265
function generateText(doc: JSONContent | Node, options?: GenerateTextOptions): string;
266
267
// Document creation
268
function createDocument(
269
content: Content,
270
schema: Schema,
271
parseOptions?: ParseOptions
272
): ProseMirrorNode;
273
function createNodeFromContent(
274
content: Content,
275
schema: Schema,
276
options?: CreateNodeFromContentOptions
277
): ProseMirrorNode | ProseMirrorNode[];
278
279
// Content queries
280
function findChildren(
281
node: ProseMirrorNode,
282
predicate: (child: ProseMirrorNode) => boolean,
283
descend?: boolean
284
): NodeWithPos[];
285
function findChildrenInRange(
286
node: ProseMirrorNode,
287
range: { from: number; to: number },
288
predicate: (child: ProseMirrorNode) => boolean,
289
descend?: boolean
290
): NodeWithPos[];
291
292
// State inspection
293
function isActive(
294
state: EditorState,
295
name?: string | NodeType | MarkType,
296
attributes?: Record<string, any>
297
): boolean;
298
function getAttributes(
299
state: EditorState,
300
nameOrType: string | NodeType | MarkType
301
): Record<string, any>;
302
```
303
304
[Document Helpers](./document-helpers.md)
305
306
### Rule Systems
307
308
Input and paste rule systems for creating shortcuts and transforming content on input or paste.
309
310
```typescript { .api }
311
class InputRule {
312
constructor(config: {
313
find: RegExp | ((value: string) => RegExpMatchArray | null);
314
handler: (props: {
315
state: EditorState;
316
range: { from: number; to: number };
317
match: RegExpMatchArray;
318
commands: SingleCommands;
319
chain: () => ChainedCommands;
320
can: () => CanCommands;
321
}) => void | null;
322
});
323
}
324
325
class PasteRule {
326
constructor(config: {
327
find: RegExp | ((value: string) => RegExpMatchArray | null);
328
handler: (props: {
329
state: EditorState;
330
range: { from: number; to: number };
331
match: RegExpMatchArray;
332
commands: SingleCommands;
333
chain: () => ChainedCommands;
334
can: () => CanCommands;
335
pastedText: string;
336
dropEvent?: DragEvent;
337
}) => void | null;
338
});
339
}
340
```
341
342
[Rule Systems](./rule-systems.md)
343
344
### JSX Runtime Support
345
346
Built-in JSX runtime support for creating custom extensions and components using JSX syntax.
347
348
```typescript { .api }
349
/**
350
* Create JSX elements for use in extensions
351
* @param type - Element type or component
352
* @param props - Element properties
353
* @param children - Child elements
354
* @returns JSX element
355
*/
356
function createElement(
357
type: string | Component,
358
props: Record<string, any> | null,
359
...children: any[]
360
): JSXElement;
361
362
/**
363
* JSX Fragment component for wrapping multiple elements
364
*/
365
const Fragment: ComponentType;
366
367
/**
368
* Alias for createElement (h stands for hyperscript)
369
*/
370
const h: typeof createElement;
371
```
372
373
**Usage Examples:**
374
375
```typescript
376
import { createElement, Fragment, h } from '@tiptap/core';
377
378
// Using createElement directly
379
const element = createElement('div', { className: 'editor-toolbar' },
380
createElement('button', { onClick: () => editor.chain().focus().toggleBold().run() }, 'Bold'),
381
createElement('button', { onClick: () => editor.chain().focus().toggleItalic().run() }, 'Italic')
382
);
383
384
// Using JSX syntax (with proper JSX transform)
385
const toolbar = (
386
<div className="editor-toolbar">
387
<button onClick={() => editor.chain().focus().toggleBold().run()}>
388
Bold
389
</button>
390
<button onClick={() => editor.chain().focus().toggleItalic().run()}>
391
Italic
392
</button>
393
</div>
394
);
395
396
// Using Fragment
397
const multipleElements = (
398
<Fragment>
399
<p>First paragraph</p>
400
<p>Second paragraph</p>
401
</Fragment>
402
);
403
404
// Using h (hyperscript style)
405
const hyperscriptElement = h('div', { id: 'editor' },
406
h('p', null, 'Content goes here')
407
);
408
409
// In custom extensions
410
const CustomExtension = Extension.create({
411
name: 'customExtension',
412
413
addNodeView() {
414
return ({ node, getPos, editor }) => {
415
const dom = createElement('div', {
416
className: 'custom-node',
417
'data-type': node.type.name
418
}, node.textContent);
419
420
return { dom };
421
};
422
}
423
});
424
```
425
426
### Utilities
427
428
Collection of utility functions for type checking, object manipulation, and platform detection.
429
430
```typescript { .api }
431
// Type guards
432
function isFunction(value: unknown): value is Function;
433
function isString(value: unknown): value is string;
434
function isNumber(value: unknown): value is number;
435
function isPlainObject(value: unknown): value is Record<string, any>;
436
437
// Object utilities
438
function mergeAttributes(...attributes: Record<string, any>[]): Record<string, any>;
439
function mergeDeep(target: Record<string, any>, source: Record<string, any>): Record<string, any>;
440
441
// Platform detection
442
function isAndroid(): boolean;
443
function isiOS(): boolean;
444
function isMacOS(): boolean;
445
446
// DOM utilities
447
function elementFromString(html: string): Element;
448
function createStyleTag(css: string, nonce?: string): HTMLStyleElement;
449
```
450
451
[Utilities](./utilities.md)
452
453
## Types
454
455
```typescript { .api }
456
// Core types
457
type Extensions = AnyExtension[];
458
type AnyExtension = Extension<any, any> | Node<any, any> | Mark<any, any>;
459
460
interface JSONContent {
461
type?: string;
462
attrs?: Record<string, any>;
463
content?: JSONContent[];
464
marks?: {
465
type: string;
466
attrs?: Record<string, any>;
467
}[];
468
text?: string;
469
}
470
471
interface NodeWithPos {
472
node: ProseMirrorNode;
473
pos: number;
474
}
475
476
// Event types
477
interface EditorEvents {
478
beforeCreate: { editor: Editor };
479
create: { editor: Editor };
480
mount: { editor: Editor };
481
unmount: { editor: Editor };
482
update: { editor: Editor; transaction: Transaction; appendedTransactions: Transaction[] };
483
selectionUpdate: { editor: Editor; transaction: Transaction };
484
transaction: { editor: Editor; transaction: Transaction };
485
focus: { editor: Editor; event: FocusEvent; transaction: Transaction };
486
blur: { editor: Editor; event: FocusEvent; transaction: Transaction };
487
contentError: {
488
editor: Editor;
489
error: Error;
490
disableCollaboration: () => void;
491
};
492
}
493
494
// Configuration types
495
interface ExtensionConfig<Options = any, Storage = any> {
496
name: string;
497
defaultOptions?: Options;
498
addStorage?(): Storage;
499
addCommands?(): Commands;
500
addKeymap?(): Record<string, any>;
501
addInputRules?(): InputRule[];
502
addPasteRules?(): PasteRule[];
503
addGlobalAttributes?(): GlobalAttributes[];
504
addNodeView?(): NodeViewRenderer;
505
onCreate?(this: { options: Options; storage: Storage }): void;
506
onUpdate?(this: { options: Options; storage: Storage }): void;
507
onDestroy?(this: { options: Options; storage: Storage }): void;
508
}
509
```