or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

autolink.mdclick-handling.mdindex.mdlink-commands.mdlink-configuration.mdpaste-processing.mdurl-validation.md

paste-processing.mddocs/

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

```