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

click-handling.mddocs/

0

# Click Handling

1

2

Click event processing for link navigation with configurable behavior and selection options. The click handler provides intelligent link navigation while respecting editor state and user preferences.

3

4

## Capabilities

5

6

### Click Handler Plugin Function

7

8

Creates a ProseMirror plugin that handles click events on links within the editor.

9

10

```typescript { .api }

11

/**

12

* Creates a ProseMirror plugin for handling link clicks

13

* @param options - Configuration options for click behavior

14

* @returns ProseMirror Plugin instance

15

*/

16

function clickHandler(options: ClickHandlerOptions): Plugin;

17

```

18

19

**Usage Examples:**

20

21

```typescript

22

import { Plugin } from "@tiptap/pm/state";

23

import { clickHandler } from "@tiptap/extension-link";

24

25

// Create click handler plugin

26

const linkClickPlugin = clickHandler({

27

type: linkMarkType,

28

editor: editorInstance,

29

enableClickSelection: true,

30

});

31

32

// Plugin is automatically used by Link extension

33

const editor = new Editor({

34

extensions: [

35

Link.configure({

36

openOnClick: true, // Enables the click handler plugin

37

enableClickSelection: false,

38

}),

39

],

40

});

41

```

42

43

### Click Handler Options Interface

44

45

Configuration interface for click handler plugin behavior and features.

46

47

```typescript { .api }

48

interface ClickHandlerOptions {

49

/**

50

* The link mark type from ProseMirror schema

51

*/

52

type: MarkType;

53

54

/**

55

* Tiptap editor instance for command access

56

*/

57

editor: Editor;

58

59

/**

60

* If enabled, clicking a link will select the entire link text

61

* @default false

62

*/

63

enableClickSelection?: boolean;

64

}

65

```

66

67

### Click Behavior Logic

68

69

The click handler implements intelligent behavior based on editor state and link attributes.

70

71

**Click Processing Flow:**

72

73

```typescript

74

// 1. Event validation (left-click only)

75

// 2. Editor editability check

76

// 3. Link element detection (direct or ancestor)

77

// 4. Attribute extraction (href, target, rel)

78

// 5. Optional link selection

79

// 6. Link navigation

80

```

81

82

**Event Filtering:**

83

84

```typescript

85

// Only processes:

86

// - Left mouse button (button === 0)

87

// - When editor is editable

88

// - When click target is a link or contains a link

89

// - When link has valid href attribute

90

91

// Ignores:

92

// - Right-click and middle-click

93

// - Clicks when editor is not editable

94

// - Clicks on non-link elements

95

// - Links without href attributes

96

```

97

98

### Link Detection

99

100

Advanced link element detection that handles various DOM structures.

101

102

```typescript { .api }

103

/**

104

* Link detection algorithm used by click handler

105

* Finds link elements in click event target hierarchy

106

*/

107

interface LinkDetection {

108

// Direct link element

109

target: HTMLAnchorElement;

110

111

// Nested link detection

112

parentTraversal: HTMLElement[];

113

114

// Link identification

115

isLinkElement: (element: HTMLElement) => element is HTMLAnchorElement;

116

}

117

```

118

119

**Detection Examples:**

120

121

```typescript

122

// Direct link click

123

<a href="https://example.com">Click me</a>

124

// ✓ Detected: event.target is HTMLAnchorElement

125

126

// Nested element click

127

<a href="https://example.com">

128

<span>Click me</span>

129

</a>

130

// ✓ Detected: traverses parent elements to find <a>

131

132

// Complex nesting

133

<a href="https://example.com">

134

<strong>

135

<em>Click me</em>

136

</strong>

137

</a>

138

// ✓ Detected: traverses multiple parent levels

139

```

140

141

### Link Selection

142

143

Optional link text selection when `enableClickSelection` is enabled.

144

145

```typescript { .api }

146

/**

147

* Link selection behavior when enableClickSelection is true

148

* Selects the entire link text range before opening

149

*/

150

interface LinkSelection {

151

/** Extend mark range to select entire link */

152

extendMarkRange: (markName: string) => void;

153

154

/** Selection happens before link navigation */

155

selectionTiming: 'before-navigation';

156

}

157

```

158

159

**Usage Examples:**

160

161

```typescript

162

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

163

import { Link } from "@tiptap/extension-link";

164

165

// Enable link selection on click

166

const editor = new Editor({

167

extensions: [

168

Link.configure({

169

openOnClick: true,

170

enableClickSelection: true, // Selects link text before opening

171

}),

172

],

173

});

174

175

// Manual link selection

176

editor.commands.extendMarkRange('link'); // Selects current link

177

```

178

179

### Link Navigation

180

181

Configurable link opening behavior with target and security attributes.

182

183

**Navigation Logic:**

184

185

```typescript

186

// 1. Extract link attributes from DOM or ProseMirror state

187

// 2. Priority: DOM attributes > ProseMirror mark attributes

188

// 3. Open link using window.open with proper target

189

// 4. Respect security attributes (rel="noopener")

190

```

191

192

**Attribute Sources:**

193

194

```typescript

195

// DOM attributes (higher priority)

196

const href = linkElement.href;

197

const target = linkElement.target;

198

199

// ProseMirror mark attributes (fallback)

200

const attrs = getAttributes(view.state, 'link');

201

const href = attrs.href;

202

const target = attrs.target;

203

```

204

205

### Advanced Click Configurations

206

207

Complex click handling configurations for different use cases.

208

209

**Conditional Link Opening:**

210

211

```typescript

212

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

213

import { Link } from "@tiptap/extension-link";

214

215

const editor = new Editor({

216

extensions: [

217

Link.configure({

218

openOnClick: true,

219

enableClickSelection: false,

220

// Custom validation through isAllowedUri affects click behavior

221

isAllowedUri: (url) => {

222

// Only allow opening of safe URLs

223

const safeDomains = ['example.com', 'tiptap.dev'];

224

try {

225

const urlObj = new URL(url);

226

return safeDomains.includes(urlObj.hostname);

227

} catch {

228

return false;

229

}

230

},

231

}),

232

],

233

});

234

```

235

236

**Editor State-Aware Clicking:**

237

238

```typescript

239

// The click handler automatically respects editor state:

240

241

// When editor is not editable:

242

editor.setEditable(false);

243

// Links still clickable (navigation only)

244

245

// When editor is editable:

246

editor.setEditable(true);

247

// Links clickable with optional selection

248

```

249

250

**Custom Click Handling:**

251

252

```typescript

253

// For custom click behavior, you can disable the built-in handler

254

// and implement your own:

255

256

const editor = new Editor({

257

extensions: [

258

Link.configure({

259

openOnClick: false, // Disable built-in click handling

260

}),

261

],

262

});

263

264

// Add custom click listener

265

editor.view.dom.addEventListener('click', (event) => {

266

const target = event.target as HTMLElement;

267

const link = target.closest('a');

268

269

if (link) {

270

event.preventDefault();

271

// Custom logic here

272

console.log('Link clicked:', link.href);

273

274

// Optional: use editor commands

275

if (confirmNavigation(link.href)) {

276

window.open(link.href, '_blank');

277

}

278

}

279

});

280

```

281

282

### Security Considerations

283

284

The click handler includes security features to prevent malicious link behavior.

285

286

**Security Features:**

287

288

```typescript

289

// 1. URL validation using configured isAllowedUri function

290

// 2. Proper target attribute handling

291

// 3. Security attributes preservation (rel="noopener")

292

// 4. XSS prevention through validation

293

// 5. Event sanitization

294

```

295

296

**Safe Link Opening:**

297

298

```typescript

299

// The click handler ensures safe link opening:

300

window.open(href, target || '_blank');

301

302

// With security attributes:

303

// rel="noopener noreferrer" prevents window.opener access

304

// target="_blank" opens in new tab/window

305

```

306

307

### Integration with Link Extension

308

309

The click handler plugin is automatically configured and managed by the Link extension.

310

311

**Automatic Integration:**

312

313

```typescript

314

// When openOnClick is enabled in Link configuration:

315

const editor = new Editor({

316

extensions: [

317

Link.configure({

318

openOnClick: true, // Automatically adds click handler plugin

319

enableClickSelection: true,

320

}),

321

],

322

});

323

324

// The Link extension automatically:

325

// 1. Creates click handler plugin with proper configuration

326

// 2. Passes editor reference and mark type

327

// 3. Configures selection behavior

328

// 4. Manages plugin lifecycle

329

```

330

331

### Performance and UX

332

333

The click handler is optimized for performance and user experience.

334

335

**Performance Features:**

336

337

```typescript

338

// 1. Efficient event filtering (left-click only)

339

// 2. Fast DOM traversal for link detection

340

// 3. Minimal attribute extraction

341

// 4. No unnecessary selection operations

342

// 5. Early returns for invalid states

343

```

344

345

**UX Considerations:**

346

347

```typescript

348

// 1. Respects editor editability state

349

// 2. Optional link text selection for visual feedback

350

// 3. Proper cursor behavior after navigation

351

// 4. Security-conscious link opening

352

// 5. Consistent behavior across different link structures

353

```

354

355

## Types

356

357

```typescript { .api }

358

/** Configuration options for click handler plugin */

359

interface ClickHandlerOptions {

360

type: MarkType;

361

editor: Editor;

362

enableClickSelection?: boolean;

363

}

364

365

/** Link element detection interface */

366

interface LinkElement extends HTMLAnchorElement {

367

href: string;

368

target?: string;

369

rel?: string;

370

}

371

```