0
# Paste Processing
1
2
Intelligent URL paste handling that automatically converts pasted URLs into clickable links. The paste handler detects when users paste URL-only content and automatically applies link formatting.
3
4
## Capabilities
5
6
### Paste Handler Plugin Function
7
8
Creates a ProseMirror plugin that processes paste events and converts URLs to links.
9
10
```typescript { .api }
11
/**
12
* Creates a ProseMirror plugin for handling URL paste operations
13
* @param options - Configuration options for paste behavior
14
* @returns ProseMirror Plugin instance
15
*/
16
function pasteHandler(options: PasteHandlerOptions): Plugin;
17
```
18
19
**Usage Examples:**
20
21
```typescript
22
import { Plugin } from "@tiptap/pm/state";
23
import { pasteHandler } from "@tiptap/extension-link";
24
25
// Create paste handler plugin
26
const linkPastePlugin = pasteHandler({
27
editor: editorInstance,
28
defaultProtocol: 'https',
29
type: linkMarkType,
30
});
31
32
// Plugin is automatically used by Link extension
33
const editor = new Editor({
34
extensions: [
35
Link.configure({
36
linkOnPaste: true, // Enables the paste handler plugin
37
defaultProtocol: 'https',
38
}),
39
],
40
});
41
```
42
43
### Paste Handler Options Interface
44
45
Configuration interface for paste handler plugin behavior and settings.
46
47
```typescript { .api }
48
interface PasteHandlerOptions {
49
/**
50
* Tiptap editor instance for command access
51
*/
52
editor: Editor;
53
54
/**
55
* Default protocol to use for protocol-less URLs
56
* @example 'https'
57
*/
58
defaultProtocol: string;
59
60
/**
61
* The link mark type from ProseMirror schema
62
*/
63
type: MarkType;
64
}
65
```
66
67
### Paste Detection Logic
68
69
The paste handler implements intelligent URL detection from pasted content.
70
71
**Detection Process:**
72
73
```typescript
74
// 1. Extract text content from paste slice
75
// 2. Check if selection is not empty (has content to replace)
76
// 3. Analyze if pasted content is pure URL
77
// 4. Validate URL using linkifyjs
78
// 5. Apply link mark to selection
79
```
80
81
**Paste Requirements:**
82
83
```typescript
84
// Paste handler activates when:
85
// 1. Selection is not empty (text is selected)
86
// 2. Pasted content is purely a URL (no additional text)
87
// 3. URL passes linkifyjs validation
88
// 4. URL matches exactly with pasted text content
89
90
// Does NOT activate when:
91
// - Nothing is selected (empty selection)
92
// - Pasted content contains mixed text and URLs
93
// - Pasted content is not a valid URL
94
// - URL doesn't match the complete pasted text
95
```
96
97
### URL Validation and Processing
98
99
Advanced URL validation using linkifyjs integration for reliable link detection.
100
101
```typescript { .api }
102
/**
103
* URL validation process used by paste handler
104
* Uses linkifyjs.find() with defaultProtocol configuration
105
*/
106
interface URLValidation {
107
/** Find URLs in text using linkifyjs */
108
findUrls: (text: string, options: { defaultProtocol: string }) => LinkMatch[];
109
110
/** Validate that URL matches complete pasted text */
111
exactMatch: (url: LinkMatch, pastedText: string) => boolean;
112
113
/** Extract href for link creation */
114
extractHref: (url: LinkMatch) => string;
115
}
116
117
interface LinkMatch {
118
isLink: boolean;
119
value: string;
120
href: string;
121
}
122
```
123
124
**Validation Examples:**
125
126
```typescript
127
// Valid paste scenarios:
128
'https://tiptap.dev' // ✓ Complete URL
129
'http://example.com/path' // ✓ Complete URL with path
130
'ftp://files.example.com' // ✓ Custom protocol (if configured)
131
'www.example.com' // ✓ Domain without protocol (adds defaultProtocol)
132
133
// Invalid paste scenarios:
134
'Visit https://tiptap.dev' // ✗ Mixed text and URL
135
'https://tiptap.dev and more' // ✗ URL with additional text
136
'not a url' // ✗ Not a valid URL
137
'' // ✗ Empty content
138
```
139
140
### Text Content Extraction
141
142
Sophisticated text extraction from ProseMirror paste slices.
143
144
```typescript { .api }
145
/**
146
* Text extraction from paste slice
147
* Handles complex ProseMirror document structures
148
*/
149
interface TextExtraction {
150
/** Extract plain text from all nodes in slice */
151
extractFromSlice: (slice: Slice) => string;
152
153
/** Handle different node types */
154
nodeTraversal: (node: Node) => string;
155
156
/** Concatenate text content */
157
textConcatenation: string;
158
}
159
```
160
161
**Extraction Process:**
162
163
```typescript
164
// Text extraction handles:
165
// 1. Multiple nodes in paste slice
166
// 2. Nested node structures
167
// 3. Text node content extraction
168
// 4. Content concatenation
169
// 5. Whitespace preservation
170
171
let textContent = '';
172
slice.content.forEach(node => {
173
textContent += node.textContent;
174
});
175
```
176
177
### Advanced Paste Configurations
178
179
Complex paste handling configurations for different use cases.
180
181
**Protocol-Aware Pasting:**
182
183
```typescript
184
import { Editor } from "@tiptap/core";
185
import { Link } from "@tiptap/extension-link";
186
187
const editor = new Editor({
188
extensions: [
189
Link.configure({
190
linkOnPaste: true,
191
defaultProtocol: 'https', // Adds https:// to protocol-less URLs
192
protocols: ['ftp', 'ssh'], // Support additional protocols
193
}),
194
],
195
});
196
197
// Paste behavior:
198
// 'example.com' → 'https://example.com'
199
// 'ftp://files.com' → 'ftp://files.com' (preserved)
200
```
201
202
**Conditional Paste Processing:**
203
204
```typescript
205
const editor = new Editor({
206
extensions: [
207
Link.configure({
208
linkOnPaste: true,
209
isAllowedUri: (url, { defaultValidate, protocols, defaultProtocol }) => {
210
// Custom paste validation
211
const allowedDomains = ['example.com', 'tiptap.dev'];
212
213
try {
214
const urlObj = new URL(url);
215
return allowedDomains.includes(urlObj.hostname);
216
} catch {
217
return false;
218
}
219
},
220
}),
221
],
222
});
223
224
// Only URLs from allowed domains will be converted to links
225
```
226
227
**Context-Sensitive Pasting:**
228
229
```typescript
230
// The paste handler respects editor context:
231
232
// In regular paragraphs:
233
editor.commands.insertContent('paragraph text');
234
editor.commands.selectAll();
235
// Paste 'https://example.com' → converts to link
236
237
// In code blocks:
238
editor.commands.setCodeBlock();
239
editor.commands.insertContent('code content');
240
editor.commands.selectAll();
241
// Paste 'https://example.com' → remains as plain text (if configured)
242
```
243
244
### Integration with Link Extension
245
246
The paste handler plugin is automatically configured and managed by the Link extension.
247
248
**Automatic Integration:**
249
250
```typescript
251
// When linkOnPaste is enabled in Link configuration:
252
const editor = new Editor({
253
extensions: [
254
Link.configure({
255
linkOnPaste: true, // Automatically adds paste handler plugin
256
defaultProtocol: 'https',
257
}),
258
],
259
});
260
261
// The Link extension automatically:
262
// 1. Creates paste handler plugin with proper configuration
263
// 2. Passes editor reference and mark type
264
// 3. Configures default protocol
265
// 4. Manages plugin lifecycle
266
```
267
268
### Performance Optimization
269
270
The paste handler is optimized for performance and user experience.
271
272
**Performance Features:**
273
274
```typescript
275
// 1. Early exit for empty selections
276
// 2. Efficient text content extraction
277
// 3. Single linkifyjs validation call
278
// 4. Minimal DOM manipulation
279
// 5. Fast exact match comparison
280
```
281
282
**UX Considerations:**
283
284
```typescript
285
// 1. Only processes selected text (clear user intent)
286
// 2. Preserves original text if URL is invalid
287
// 3. Seamless link creation for valid URLs
288
// 4. Respects existing link marks
289
// 5. Works with undo/redo system
290
```
291
292
### Error Handling
293
294
Robust error handling for various paste scenarios and edge cases.
295
296
**Error Prevention:**
297
298
```typescript
299
// 1. Graceful handling of invalid URLs
300
// 2. Safe text extraction from complex slices
301
// 3. Fallback to original paste behavior
302
// 4. Validation of linkifyjs results
303
// 5. Protection against malformed paste data
304
```
305
306
**Edge Case Handling:**
307
308
```typescript
309
// Handles edge cases:
310
// - Empty paste content
311
// - Binary/non-text paste data
312
// - Malformed URLs
313
// - Very long URLs
314
// - Unicode characters in URLs
315
// - Protocol-less URLs with custom protocols
316
```
317
318
### Command Integration
319
320
The paste handler integrates with Tiptap's command system for consistent behavior.
321
322
**Command Usage:**
323
324
```typescript
325
// The paste handler uses editor.commands.setMark() internally:
326
return options.editor.commands.setMark(options.type, {
327
href: link.href,
328
});
329
330
// This ensures:
331
// 1. Proper mark application
332
// 2. Transaction creation
333
// 3. Undo/redo support
334
// 4. Event emission
335
// 5. Plugin coordination
336
```
337
338
## Types
339
340
```typescript { .api }
341
/** Configuration options for paste handler plugin */
342
interface PasteHandlerOptions {
343
editor: Editor;
344
defaultProtocol: string;
345
type: MarkType;
346
}
347
348
/** Link match result from linkifyjs */
349
interface LinkMatch {
350
isLink: boolean;
351
value: string;
352
href: string;
353
}
354
355
/** ProseMirror slice for paste content */
356
interface Slice {
357
content: Fragment;
358
openStart: number;
359
openEnd: number;
360
}
361
```