0
# Quill
1
2
Quill is a modern, powerful rich text editor built for compatibility and extensibility. It provides a comprehensive WYSIWYG editing experience with support for operational transformation, custom formatting, modular architecture, and extensive theming capabilities. The library offers both programmatic API access and user-friendly toolbar interfaces, supports multiple output formats including Delta (its native format), HTML, and plain text, and includes built-in modules for clipboard handling, keyboard shortcuts, history/undo-redo functionality, and toolbar management.
3
4
## Package Information
5
6
- **Package Name**: quill
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install quill`
10
11
## Core Imports
12
13
```typescript
14
import Quill from "quill";
15
```
16
17
For CommonJS:
18
19
```javascript
20
const Quill = require("quill");
21
```
22
23
## Basic Usage
24
25
```typescript
26
import Quill from "quill";
27
28
// Initialize Quill editor
29
const quill = new Quill('#editor', {
30
theme: 'snow',
31
modules: {
32
toolbar: [
33
['bold', 'italic', 'underline'],
34
['link', 'image'],
35
[{ 'header': [1, 2, 3, false] }],
36
[{ 'list': 'ordered'}, { 'list': 'bullet' }]
37
]
38
}
39
});
40
41
// Get/set content
42
const content = quill.getContents();
43
quill.setContents(content);
44
45
// Listen for changes
46
quill.on('text-change', (delta, oldDelta, source) => {
47
console.log('Text changed:', delta);
48
});
49
```
50
51
## Architecture
52
53
Quill is built around several key components:
54
55
- **Delta System**: Operational transform-based document representation using Delta format for change tracking
56
- **Blot System**: Parchment-based document model where content is represented as structured blots (blocks, inlines, embeds)
57
- **Module Architecture**: Extensible plugin system with core modules (History, Keyboard, Clipboard, Toolbar)
58
- **Theme System**: UI layer providing Snow (toolbar above) and Bubble (floating toolbar) themes
59
- **Event System**: Comprehensive event emission for text changes, selection changes, and editor interactions
60
- **Format Registry**: Dynamic registration system for custom formats, blots, modules, and themes
61
62
## Capabilities
63
64
### Editor Core
65
66
Core editor functionality for creating and managing rich text editor instances. The main Quill class provides all essential editing operations.
67
68
```typescript { .api }
69
class Quill {
70
constructor(container: HTMLElement | string, options?: QuillOptions);
71
72
// Content operations
73
getContents(index?: number, length?: number): Delta;
74
setContents(delta: Delta | Op[], source?: EmitterSource): Delta;
75
updateContents(delta: Delta | Op[], source?: EmitterSource): Delta;
76
getText(index?: number, length?: number): string;
77
setText(text: string, source?: EmitterSource): Delta;
78
getSemanticHTML(range: Range): string;
79
getSemanticHTML(index?: number, length?: number): string;
80
81
// Selection operations
82
getSelection(focus?: boolean): Range | null;
83
setSelection(range: Range | null, source?: EmitterSource): void;
84
setSelection(index: number, length?: number, source?: EmitterSource): void;
85
getBounds(index: number | Range, length?: number): Bounds | null;
86
87
// Formatting operations
88
format(name: string, value: unknown, source?: EmitterSource): Delta;
89
formatText(index: number, length: number, formats: Record<string, unknown>, source?: EmitterSource): Delta;
90
formatLine(index: number, length: number, formats: Record<string, unknown>, source?: EmitterSource): Delta;
91
removeFormat(index: number, length: number, source?: EmitterSource): Delta;
92
getFormat(index?: number, length?: number): { [format: string]: unknown };
93
94
// Text operations
95
insertText(index: number, text: string, formats?: Record<string, unknown>, source?: EmitterSource): Delta;
96
insertEmbed(index: number, embed: string, value: unknown, source?: EmitterSource): Delta;
97
deleteText(index: number, length: number, source?: EmitterSource): Delta;
98
99
// Editor state
100
focus(options?: { preventScroll?: boolean }): void;
101
blur(): void;
102
enable(enabled?: boolean): void;
103
disable(): void;
104
isEnabled(): boolean;
105
hasFocus(): boolean;
106
107
// Event handling
108
on(event: string, handler: (...args: any[]) => void): Emitter;
109
off(event: string, handler?: (...args: any[]) => void): Emitter;
110
once(event: string, handler: (...args: any[]) => void): Emitter;
111
112
// Additional content methods
113
getIndex(blot: Parchment.Blot): number;
114
getLeaf(index: number): [Parchment.Leaf | null, number];
115
getLine(index: number): [Parchment.Block | Parchment.BlockEmbed | null, number];
116
getLines(index?: number, length?: number): (Parchment.Block | Parchment.BlockEmbed)[];
117
getLines(range: Range): (Parchment.Block | Parchment.BlockEmbed)[];
118
119
// Container management
120
addContainer(container: string, refNode?: Node | null): HTMLDivElement;
121
addContainer(container: HTMLElement, refNode?: Node | null): HTMLElement;
122
123
// Advanced editing
124
editReadOnly<T>(modifier: () => T): T;
125
scrollRectIntoView(rect: { top: number; left: number; right: number; bottom: number }): void;
126
127
// Deprecated methods
128
scrollIntoView(): void; // @deprecated Use scrollSelectionIntoView()
129
130
// Utility methods
131
getLength(): number;
132
getModule(name: string): Module;
133
scrollSelectionIntoView(): void;
134
update(source?: EmitterSource): Delta | undefined;
135
// Static methods
136
static debug(level: DebugLevel | boolean): void;
137
static find(node: Node, bubble?: boolean): Parchment.Blot | null;
138
static import(name: string): unknown;
139
static register(path: string, target: any, overwrite?: boolean): void;
140
static register(target: Record<string, any>, overwrite?: boolean): void;
141
static register(target: Parchment.RegistryDefinition, overwrite?: boolean): void;
142
143
// Static properties
144
static DEFAULTS: Partial<QuillOptions>;
145
static events: typeof Emitter.events;
146
static sources: typeof Emitter.sources;
147
static version: string;
148
}
149
150
interface QuillOptions {
151
theme?: string;
152
debug?: DebugLevel | boolean;
153
registry?: Parchment.Registry;
154
readOnly?: boolean;
155
placeholder?: string;
156
bounds?: HTMLElement | string | null;
157
modules?: Record<string, unknown>;
158
formats?: string[] | null;
159
}
160
161
interface Range {
162
index: number;
163
length: number;
164
}
165
166
interface Bounds {
167
bottom: number;
168
height: number;
169
left: number;
170
right: number;
171
top: number;
172
width: number;
173
}
174
175
type EmitterSource = 'api' | 'user' | 'silent';
176
type DebugLevel = 'error' | 'warn' | 'log' | 'info';
177
178
interface Emitter {
179
on(event: string, handler: (...args: any[]) => void): Emitter;
180
off(event: string, handler?: (...args: any[]) => void): Emitter;
181
once(event: string, handler: (...args: any[]) => void): Emitter;
182
emit(event: string, ...args: any[]): void;
183
}
184
185
namespace Emitter {
186
const events = {
187
TEXT_CHANGE: 'text-change',
188
SELECTION_CHANGE: 'selection-change',
189
EDITOR_CHANGE: 'editor-change'
190
};
191
const sources = {
192
API: 'api' as EmitterSource,
193
USER: 'user' as EmitterSource,
194
SILENT: 'silent' as EmitterSource
195
};
196
}
197
```
198
199
[Editor Core](./editor-core.md)
200
201
### Delta Operations
202
203
Delta-based document representation and operational transform system for tracking and applying changes to rich text content.
204
205
```typescript { .api }
206
class Delta {
207
constructor(ops?: Op[] | Delta);
208
209
// Core operations
210
insert(text: string, attributes?: AttributeMap): Delta;
211
insert(embed: object, attributes?: AttributeMap): Delta;
212
delete(length: number): Delta;
213
retain(length: number, attributes?: AttributeMap): Delta;
214
215
// Delta manipulation
216
compose(other: Delta): Delta;
217
transform(other: Delta, priority?: boolean): Delta;
218
transformPosition(index: number, priority?: boolean): number;
219
diff(other: Delta, cursor?: number): Delta;
220
221
// Utility methods
222
length(): number;
223
slice(start?: number, end?: number): Delta;
224
partition(predicate: (op: Op) => boolean): [Delta, Delta];
225
filter(predicate: (op: Op, index: number) => boolean): Op[];
226
forEach(predicate: (op: Op, index: number) => void): void;
227
map<T>(predicate: (op: Op, index: number) => T): T[];
228
reduce<T>(predicate: (acc: T, curr: Op, index: number) => T, initialValue: T): T;
229
}
230
231
interface Op {
232
insert?: string | object;
233
delete?: number;
234
retain?: number;
235
attributes?: AttributeMap;
236
}
237
238
interface AttributeMap {
239
[key: string]: unknown;
240
}
241
```
242
243
[Delta Operations](./delta-operations.md)
244
245
### Formatting System
246
247
Comprehensive formatting system supporting inline formats (bold, italic, links), block formats (headers, lists, blockquotes), and custom attributors.
248
249
```typescript { .api }
250
// Built-in inline formats
251
class Bold extends Inline {
252
static blotName: 'bold';
253
static tagName: ['STRONG', 'B'];
254
}
255
256
class Italic extends Inline {
257
static blotName: 'italic';
258
static tagName: ['EM', 'I'];
259
}
260
261
class Link extends Inline {
262
static blotName: 'link';
263
static tagName: 'A';
264
static create(value: string): HTMLAnchorElement;
265
static formats(domNode: HTMLAnchorElement): string;
266
static sanitize(url: string): string;
267
}
268
269
// Built-in block formats
270
class Header extends Block {
271
static blotName: 'header';
272
static tagName: ['H1', 'H2', 'H3', 'H4', 'H5', 'H6'];
273
static formats(domNode: HTMLElement): number;
274
}
275
276
class List extends Block {
277
static blotName: 'list';
278
static tagName: 'LI';
279
static create(value: 'ordered' | 'bullet'): HTMLLIElement;
280
static formats(domNode: HTMLLIElement): string;
281
}
282
283
// Embed formats
284
class Image extends EmbedBlot {
285
static blotName: 'image';
286
static tagName: 'IMG';
287
static create(value: string): HTMLImageElement;
288
static formats(domNode: HTMLImageElement): Record<string, string>;
289
static value(domNode: HTMLImageElement): string;
290
}
291
```
292
293
[Formatting System](./formatting-system.md)
294
295
### Module System
296
297
Extensible module architecture with core modules for history, keyboard, clipboard, toolbar, and upload functionality.
298
299
```typescript { .api }
300
abstract class Module {
301
static DEFAULTS: Record<string, unknown>;
302
constructor(quill: Quill, options?: Record<string, unknown>);
303
}
304
305
class History extends Module {
306
static DEFAULTS: {
307
delay: number;
308
maxStack: number;
309
userOnly: boolean;
310
};
311
312
clear(): void;
313
cutoff(): void;
314
undo(): void;
315
redo(): void;
316
}
317
318
class Toolbar extends Module {
319
static DEFAULTS: {
320
container?: string | HTMLElement | (string | Record<string, unknown>)[];
321
handlers?: Record<string, ToolbarHandler>;
322
};
323
324
addHandler(format: string, handler: ToolbarHandler): void;
325
attach(input: HTMLElement): void;
326
update(range: Range | null): void;
327
}
328
329
class Clipboard extends Module {
330
addMatcher(selector: string, matcher: ClipboardMatcher): void;
331
dangerouslyPasteHTML(html: string, source?: EmitterSource): void;
332
convert(clipboard: { html?: string; text?: string }): Delta;
333
}
334
335
type ToolbarHandler = (value: unknown) => void;
336
type ClipboardMatcher = (node: Node, delta: Delta) => Delta;
337
```
338
339
[Module System](./module-system.md)
340
341
### Theme System
342
343
Theme system providing Snow and Bubble themes with customizable UI components and toolbar layouts.
344
345
```typescript { .api }
346
abstract class Theme {
347
static DEFAULTS: Record<string, unknown>;
348
constructor(quill: Quill, options: Record<string, unknown>);
349
350
init(): void;
351
addModule(name: string): Module;
352
}
353
354
class SnowTheme extends Theme {
355
// Snow theme with toolbar above editor
356
}
357
358
class BubbleTheme extends Theme {
359
// Bubble theme with floating toolbar
360
}
361
```
362
363
[Theme System](./theme-system.md)
364
365
### Registry System
366
367
Dynamic registration system for formats, modules, themes, and blots enabling extensibility and customization.
368
369
```typescript { .api }
370
class Quill {
371
static register(path: string, target: any, overwrite?: boolean): void;
372
static register(target: Record<string, any>, overwrite?: boolean): void;
373
static register(target: RegistryDefinition, overwrite?: boolean): void;
374
375
static import(name: string): unknown;
376
static find(node: Node, bubble?: boolean): Blot | null;
377
static debug(level: DebugLevel | boolean): void;
378
}
379
380
// Registration paths
381
// 'formats/bold' - Register Bold format
382
// 'modules/toolbar' - Register Toolbar module
383
// 'themes/snow' - Register Snow theme
384
// 'blots/block' - Register Block blot
385
// 'attributors/style/color' - Register style-based color attributor
386
```
387
388
[Registry System](./registry-system.md)
389
390
## Types
391
392
```typescript { .api }
393
// Re-exported from quill-delta
394
interface Delta {
395
ops: Op[];
396
}
397
398
interface Op {
399
insert?: string | object;
400
delete?: number;
401
retain?: number;
402
attributes?: AttributeMap;
403
}
404
405
interface AttributeMap {
406
[key: string]: unknown;
407
}
408
409
class OpIterator {
410
constructor(ops: Op[]);
411
hasNext(): boolean;
412
next(length?: number): Op;
413
peek(): Op;
414
peekLength(): number;
415
peekType(): 'insert' | 'delete' | 'retain';
416
rest(): Op[];
417
}
418
419
// Re-exported from parchment
420
namespace Parchment {
421
abstract class Blot {
422
static blotName: string;
423
static className?: string;
424
static tagName?: string | string[];
425
static scope: Scope;
426
427
domNode: Node;
428
parent: Blot | null;
429
prev: Blot | null;
430
next: Blot | null;
431
432
constructor(scroll: ScrollBlot, domNode?: Node);
433
434
attach(): void;
435
clone(): Blot;
436
detach(): void;
437
deleteAt(index: number, length: number): void;
438
formatAt(index: number, length: number, name: string, value: any): void;
439
insertAt(index: number, value: string, def?: any): void;
440
isolate(index: number, length: number): Blot;
441
length(): number;
442
offset(root?: Blot): number;
443
optimize(context: any): void;
444
remove(): void;
445
replaceWith(name: string | Blot, value?: any): Blot;
446
split(index: number, force?: boolean): Blot | null;
447
update(mutations: MutationRecord[], context: any): void;
448
wrap(name: string | Blot, value?: any): Blot;
449
}
450
451
enum Scope {
452
TYPE = 3,
453
LEVEL = 12,
454
ATTRIBUTE = 13,
455
BLOT = 14,
456
INLINE = 7,
457
BLOCK = 11,
458
BLOCK_BLOT = 10,
459
INLINE_BLOT = 6,
460
LEAF = 4,
461
PARENT = 8,
462
ANY = 15
463
}
464
465
class Registry {
466
create(scroll: ScrollBlot, input: Node | string | Scope, value?: any): Blot;
467
find(domNode: Node, bubble?: boolean): Blot | null;
468
query(query: string | Node | Scope, scope?: Scope): BlotConstructor | null;
469
register(...definitions: RegistryDefinition[]): void;
470
}
471
}
472
```