or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

command-system.mddocument-helpers.mdeditor-core.mdextension-system.mdindex.mdrule-systems.mdutilities.md

editor-core.mddocs/

0

# Editor Core

1

2

The Editor class is the central component of @tiptap/core, managing the editor state, view, extensions, and providing the main API interface for interacting with the rich text editor.

3

4

## Capabilities

5

6

### Editor Constructor

7

8

Creates a new editor instance with the specified configuration options.

9

10

```typescript { .api }

11

/**

12

* Creates a new Tiptap editor instance

13

* @param options - Configuration options for the editor

14

*/

15

constructor(options: Partial<EditorOptions>): Editor;

16

17

interface EditorOptions {

18

/** The DOM element to mount the editor to */

19

element?: Element;

20

21

/** Initial content for the editor */

22

content?: Content;

23

24

/** Array of extensions to load */

25

extensions?: Extensions;

26

27

/** Whether to inject default CSS styles */

28

injectCSS?: boolean;

29

30

/** Initial focus position */

31

autofocus?: FocusPosition;

32

33

/** Whether the editor should be editable */

34

editable?: boolean;

35

36

/** Enable input rules (markdown-like shortcuts) */

37

enableInputRules?: boolean;

38

39

/** Enable paste rules */

40

enablePasteRules?: boolean;

41

42

/** Enable core extensions */

43

enableCoreExtensions?: boolean;

44

45

/** Callback fired before editor creation */

46

onBeforeCreate?(props: EditorEvents['beforeCreate']): void;

47

48

/** Callback fired after editor creation */

49

onCreate?(props: EditorEvents['create']): void;

50

51

/** Callback fired on content updates */

52

onUpdate?(props: EditorEvents['update']): void;

53

54

/** Callback fired on selection updates */

55

onSelectionUpdate?(props: EditorEvents['selectionUpdate']): void;

56

57

/** Callback fired on transactions */

58

onTransaction?(props: EditorEvents['transaction']): void;

59

60

/** Callback fired on focus */

61

onFocus?(props: EditorEvents['focus']): void;

62

63

/** Callback fired on blur */

64

onBlur?(props: EditorEvents['blur']): void;

65

66

/** Callback fired when editor is destroyed */

67

onDestroy?(): void;

68

}

69

70

type Content =

71

| string

72

| JSONContent

73

| JSONContent[]

74

| ProseMirrorNode

75

| null;

76

77

type FocusPosition =

78

| boolean

79

| 'start'

80

| 'end'

81

| 'all'

82

| number

83

| { from: number; to?: number };

84

```

85

86

**Usage Examples:**

87

88

```typescript

89

import { Editor } from '@tiptap/core';

90

91

// Basic editor

92

const editor = new Editor({

93

element: document.querySelector('#editor'),

94

content: '<p>Hello World!</p>'

95

});

96

97

// Editor with callbacks

98

const editor = new Editor({

99

element: document.querySelector('#editor'),

100

content: '<p>Hello World!</p>',

101

autofocus: 'end',

102

editable: true,

103

onUpdate: ({ editor }) => {

104

console.log('Content updated:', editor.getHTML());

105

},

106

onFocus: ({ editor, event }) => {

107

console.log('Editor focused');

108

}

109

});

110

```

111

112

### Core Properties

113

114

Essential properties for inspecting the editor state and configuration.

115

116

```typescript { .api }

117

/** ProseMirror EditorView instance (proxied when unmounted) */

118

readonly view: EditorView;

119

120

/** Current ProseMirror EditorState */

121

readonly state: EditorState;

122

123

/** ProseMirror Schema built from extensions */

124

readonly schema: Schema;

125

126

/** Storage object shared between extensions */

127

readonly storage: Storage;

128

129

/** Whether the editor accepts input */

130

readonly isEditable: boolean;

131

132

/** Whether the editor currently has focus */

133

readonly isFocused: boolean;

134

135

/** Whether the editor content is empty */

136

readonly isEmpty: boolean;

137

138

/** Whether the editor has been destroyed */

139

readonly isDestroyed: boolean;

140

141

/** Whether the editor is fully initialized */

142

readonly isInitialized: boolean;

143

```

144

145

### Lifecycle Management

146

147

Methods for managing the editor lifecycle - mounting, unmounting, and destroying.

148

149

```typescript { .api }

150

/**

151

* Mount the editor to a DOM element

152

* @param element - Optional DOM element to mount to (uses constructor element if not provided)

153

* @returns The editor instance for chaining

154

*/

155

mount(element?: Element): Editor;

156

157

/**

158

* Unmount the editor from DOM while preserving the instance for potential remounting

159

* @returns The editor instance for chaining

160

*/

161

unmount(): Editor;

162

163

/**

164

* Permanently destroy the editor instance and clean up resources

165

*/

166

destroy(): void;

167

```

168

169

**Usage Examples:**

170

171

```typescript

172

// Create editor without mounting

173

const editor = new Editor({

174

content: '<p>Hello World!</p>'

175

});

176

177

// Mount later

178

editor.mount(document.querySelector('#editor'));

179

180

// Temporarily unmount (can be remounted)

181

editor.unmount();

182

183

// Mount to different element

184

editor.mount(document.querySelector('#another-editor'));

185

186

// Permanently destroy

187

editor.destroy();

188

```

189

190

### Command Execution

191

192

Core command execution interface providing single commands, command chains, and command validation.

193

194

```typescript { .api }

195

/** Access to all registered commands for single execution */

196

readonly commands: SingleCommands;

197

198

/**

199

* Create a command chain for executing multiple commands in sequence

200

* @returns ChainedCommands instance

201

*/

202

chain(): ChainedCommands;

203

204

/**

205

* Create a command validation interface

206

* @returns CanCommands instance for testing command executability

207

*/

208

can(): CanCommands;

209

210

interface SingleCommands {

211

[commandName: string]: (attributes?: Record<string, any>) => boolean;

212

}

213

214

interface ChainedCommands {

215

[commandName: string]: (attributes?: Record<string, any>) => ChainedCommands;

216

/** Execute the command chain */

217

run(): boolean;

218

}

219

220

interface CanCommands {

221

[commandName: string]: (attributes?: Record<string, any>) => boolean;

222

}

223

```

224

225

**Usage Examples:**

226

227

```typescript

228

// Single command execution

229

const success = editor.commands.setBold();

230

231

// Command chaining

232

editor

233

.chain()

234

.focus()

235

.setBold()

236

.setItalic()

237

.insertContent('Bold and italic text')

238

.run();

239

240

// Command validation

241

if (editor.can().setBold()) {

242

editor.commands.setBold();

243

}

244

245

// Conditional chaining

246

editor

247

.chain()

248

.focus()

249

.toggleBold()

250

.insertContent(editor.can().setItalic() ? 'Can italicize' : 'Cannot italicize')

251

.run();

252

```

253

254

### Content Management

255

256

Methods for retrieving and setting editor content in various formats.

257

258

```typescript { .api }

259

/**

260

* Get editor content as HTML string

261

* @returns HTML representation of the document

262

*/

263

getHTML(): string;

264

265

/**

266

* Get editor content as JSON

267

* @returns JSONContent representation of the document

268

*/

269

getJSON(): JSONContent;

270

271

/**

272

* Get editor content as plain text

273

* @param options - Text extraction options

274

* @returns Plain text content

275

*/

276

getText(options?: GetTextOptions): string;

277

278

interface GetTextOptions {

279

/** Include block separators (default: true) */

280

blockSeparator?: string;

281

/** Include text between given positions */

282

from?: number;

283

to?: number;

284

}

285

286

interface JSONContent {

287

type?: string;

288

attrs?: Record<string, any>;

289

content?: JSONContent[];

290

marks?: Array<{

291

type: string;

292

attrs?: Record<string, any>;

293

}>;

294

text?: string;

295

}

296

```

297

298

**Usage Examples:**

299

300

```typescript

301

// Get content in different formats

302

const htmlContent = editor.getHTML();

303

// '<p><strong>Bold text</strong></p>'

304

305

const jsonContent = editor.getJSON();

306

// { type: 'doc', content: [{ type: 'paragraph', content: [...] }] }

307

308

const plainText = editor.getText();

309

// 'Bold text'

310

311

const textWithCustomSeparator = editor.getText({

312

blockSeparator: ' | '

313

});

314

315

// Get text from specific range

316

const rangeText = editor.getText({

317

from: 0,

318

to: 10

319

});

320

```

321

322

### Configuration Management

323

324

Methods for updating editor configuration and behavior at runtime.

325

326

```typescript { .api }

327

/**

328

* Update editor options

329

* @param options - Partial options to update

330

*/

331

setOptions(options: Partial<EditorOptions>): void;

332

333

/**

334

* Change the editable state of the editor

335

* @param editable - Whether the editor should be editable

336

*/

337

setEditable(editable: boolean): void;

338

339

/**

340

* Register a new ProseMirror plugin

341

* @param plugin - ProseMirror plugin to register

342

* @param handlePlugins - Optional function to handle plugin conflicts

343

*/

344

registerPlugin(

345

plugin: Plugin,

346

handlePlugins?: (newPlugin: Plugin, existingPlugins: Plugin[]) => Plugin[]

347

): void;

348

349

/**

350

* Unregister a ProseMirror plugin

351

* @param nameOrKey - Plugin name or PluginKey to remove

352

*/

353

unregisterPlugin(nameOrKey: string | PluginKey): void;

354

```

355

356

**Usage Examples:**

357

358

```typescript

359

// Update editor options

360

editor.setOptions({

361

editable: false,

362

onUpdate: ({ editor }) => {

363

console.log('New update handler');

364

}

365

});

366

367

// Toggle editable state

368

editor.setEditable(false); // Make read-only

369

editor.setEditable(true); // Make editable again

370

371

// Register custom plugin

372

import { Plugin, PluginKey } from '@tiptap/pm/state';

373

374

const customPluginKey = new PluginKey('customPlugin');

375

const customPlugin = new Plugin({

376

key: customPluginKey,

377

// plugin implementation

378

});

379

380

editor.registerPlugin(customPlugin);

381

382

// Unregister plugin

383

editor.unregisterPlugin('customPlugin');

384

// or

385

editor.unregisterPlugin(customPluginKey);

386

```

387

388

### State Inspection

389

390

Methods for inspecting the current editor state and selection.

391

392

```typescript { .api }

393

/**

394

* Get attributes of the current selection

395

* @param nameOrType - Node/mark name, NodeType, or MarkType

396

* @returns Attributes object

397

*/

398

getAttributes(nameOrType: string | NodeType | MarkType): Record<string, any>;

399

400

/**

401

* Check if a node or mark is active in the current selection

402

* @param name - Node or mark name to check

403

* @param attributes - Optional attributes to match

404

* @returns Whether the node/mark is active

405

*/

406

isActive(name: string, attributes?: Record<string, any>): boolean;

407

```

408

409

**Usage Examples:**

410

411

```typescript

412

// Check if formatting is active

413

const isBold = editor.isActive('bold');

414

const isItalic = editor.isActive('italic');

415

const isHeading = editor.isActive('heading', { level: 1 });

416

417

// Get current attributes

418

const linkAttrs = editor.getAttributes('link');

419

// { href: 'https://example.com', target: '_blank' }

420

421

const headingAttrs = editor.getAttributes('heading');

422

// { level: 2 }

423

424

// Use in UI state

425

function BoldButton() {

426

const isActive = editor.isActive('bold');

427

return (

428

<button

429

className={isActive ? 'active' : ''}

430

onClick={() => editor.chain().focus().toggleBold().run()}

431

>

432

Bold

433

</button>

434

);

435

}

436

```

437

438

### Content Querying

439

440

Advanced methods for querying and navigating the document structure.

441

442

```typescript { .api }

443

/**

444

* Create a NodePos instance at the specified position

445

* @param pos - Document position

446

* @returns NodePos for advanced position operations

447

*/

448

$pos(pos: number): NodePos;

449

450

/**

451

* Find a single node matching the selector and attributes

452

* @param selector - Node type selector

453

* @param attributes - Optional attributes to match

454

* @returns NodePos if found, null otherwise

455

*/

456

$node(selector: string, attributes?: Record<string, any>): NodePos | null;

457

458

/**

459

* Find all nodes matching the selector and attributes

460

* @param selector - Node type selector

461

* @param attributes - Optional attributes to match

462

* @returns Array of NodePos instances

463

*/

464

$nodes(selector: string, attributes?: Record<string, any>): NodePos[];

465

```

466

467

**Usage Examples:**

468

469

```typescript

470

// Get position info

471

const pos = editor.$pos(10);

472

console.log(pos.node()); // Node at position

473

console.log(pos.parent); // Parent node

474

475

// Find specific nodes

476

const firstHeading = editor.$node('heading');

477

const h1 = editor.$node('heading', { level: 1 });

478

479

// Find all nodes of a type

480

const allParagraphs = editor.$nodes('paragraph');

481

const allImages = editor.$nodes('image');

482

483

// Advanced querying

484

const allH2WithClass = editor.$nodes('heading', {

485

level: 2,

486

class: 'special'

487

});

488

489

// Navigate and modify

490

const heading = editor.$node('heading');

491

if (heading) {

492

heading.content = 'Updated heading content';

493

heading.setAttribute({ level: 2 });

494

}

495

```

496

497

### NodePos Class

498

499

The NodePos class provides a DOM-like interface for navigating and manipulating nodes in the document. It offers powerful querying and modification capabilities similar to browser DOM APIs.

500

501

```typescript { .api }

502

/**

503

* Represents a position in the document with DOM-like navigation and manipulation capabilities

504

*/

505

class NodePos {

506

/** The ProseMirror node at this position */

507

readonly node: Node;

508

509

/** The document position */

510

readonly pos: number;

511

512

/** The depth in the document tree */

513

readonly depth: number;

514

515

/** Node attributes */

516

readonly attributes: Record<string, any>;

517

518

/** Node text content */

519

readonly textContent: string;

520

521

/** Node size in the document */

522

readonly size: number;

523

524

/** Start position of the node */

525

readonly from: number;

526

527

/** End position of the node */

528

readonly to: number;

529

530

/** Node range (from/to positions) */

531

readonly range: Range;

532

533

/** Corresponding DOM element */

534

readonly element: HTMLElement;

535

536

/** Node content fragment */

537

content: Fragment;

538

539

// Navigation properties

540

/** Parent node (null if at root) */

541

readonly parent: NodePos | null;

542

543

/** Previous sibling node */

544

readonly before: NodePos | null;

545

546

/** Next sibling node */

547

readonly after: NodePos | null;

548

549

/** Child nodes array */

550

readonly children: NodePos[];

551

552

/** First child node */

553

readonly firstChild: NodePos | null;

554

555

/** Last child node */

556

readonly lastChild: NodePos | null;

557

558

// Query methods

559

/**

560

* Find the closest ancestor matching the selector

561

* @param selector - Node type to search for

562

* @param attributes - Optional attributes to match

563

* @returns Closest matching ancestor or null

564

*/

565

closest(selector: string, attributes?: Record<string, any>): NodePos | null;

566

567

/**

568

* Find first descendant matching the selector

569

* @param selector - Node type to search for

570

* @param attributes - Optional attributes to match

571

* @returns First matching descendant or null

572

*/

573

querySelector(selector: string, attributes?: Record<string, any>): NodePos | null;

574

575

/**

576

* Find all descendants matching the selector

577

* @param selector - Node type to search for

578

* @param attributes - Optional attributes to match

579

* @returns Array of matching descendants

580

*/

581

querySelectorAll(selector: string, attributes?: Record<string, any>): NodePos[];

582

583

// Modification methods

584

/**

585

* Set attributes on this node

586

* @param attributes - Attributes to set

587

*/

588

setAttribute(attributes: Record<string, any>): void;

589

}

590

591

interface Range {

592

from: number;

593

to: number;

594

}

595

```

596

597

**Usage Examples:**

598

599

```typescript

600

// DOM-like navigation

601

const pos = editor.$pos(50);

602

const parent = pos.parent;

603

const children = pos.children;

604

const firstChild = pos.firstChild;

605

606

// Query for specific nodes

607

const heading = pos.querySelector('heading');

608

const allParagraphs = pos.querySelectorAll('paragraph');

609

const h1WithId = pos.querySelector('heading', { level: 1, id: 'main' });

610

611

// Navigate relationships

612

const nextHeading = pos.closest('heading')?.after?.querySelector('heading');

613

614

// Content manipulation

615

const paragraph = editor.$node('paragraph');

616

if (paragraph) {

617

paragraph.content = 'New paragraph content';

618

paragraph.setAttribute({ class: 'highlighted' });

619

}

620

621

// Range operations

622

const range = paragraph?.range;

623

if (range) {

624

editor.commands.setTextSelection(range);

625

}

626

627

// Complex navigation

628

const headings = editor.$nodes('heading');

629

headings.forEach(heading => {

630

const level = heading.attributes.level;

631

console.log(`H${level}: ${heading.textContent}`);

632

633

// Find all paragraphs under this heading

634

const paragraphs = heading.querySelectorAll('paragraph');

635

console.log(`Contains ${paragraphs.length} paragraphs`);

636

});

637

638

// Tree traversal

639

function walkNodes(nodePos: NodePos, callback: (node: NodePos) => void) {

640

callback(nodePos);

641

nodePos.children.forEach(child => walkNodes(child, callback));

642

}

643

644

walkNodes(editor.$pos(0), node => {

645

console.log(`${node.node.type.name} at ${node.pos}`);

646

});

647

```