CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-tiptap--extension-link

Link extension for tiptap rich text editor providing automatic link detection, paste handling, click behavior, and XSS protection.

88

1.23x
Overview
Eval results
Files

click-handling.mddocs/

Click Handling

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.

Capabilities

Click Handler Plugin Function

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

/**
 * Creates a ProseMirror plugin for handling link clicks
 * @param options - Configuration options for click behavior
 * @returns ProseMirror Plugin instance
 */
function clickHandler(options: ClickHandlerOptions): Plugin;

Usage Examples:

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

// Create click handler plugin
const linkClickPlugin = clickHandler({
  type: linkMarkType,
  editor: editorInstance,
  enableClickSelection: true,
});

// Plugin is automatically used by Link extension
const editor = new Editor({
  extensions: [
    Link.configure({
      openOnClick: true, // Enables the click handler plugin
      enableClickSelection: false,
    }),
  ],
});

Click Handler Options Interface

Configuration interface for click handler plugin behavior and features.

interface ClickHandlerOptions {
  /**
   * The link mark type from ProseMirror schema
   */
  type: MarkType;

  /**
   * Tiptap editor instance for command access
   */
  editor: Editor;

  /**
   * If enabled, clicking a link will select the entire link text
   * @default false
   */
  enableClickSelection?: boolean;
}

Click Behavior Logic

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

Click Processing Flow:

// 1. Event validation (left-click only)
// 2. Editor editability check
// 3. Link element detection (direct or ancestor)
// 4. Attribute extraction (href, target, rel)
// 5. Optional link selection
// 6. Link navigation

Event Filtering:

// Only processes:
// - Left mouse button (button === 0)
// - When editor is editable
// - When click target is a link or contains a link
// - When link has valid href attribute

// Ignores:
// - Right-click and middle-click
// - Clicks when editor is not editable
// - Clicks on non-link elements
// - Links without href attributes

Link Detection

Advanced link element detection that handles various DOM structures.

/**
 * Link detection algorithm used by click handler
 * Finds link elements in click event target hierarchy
 */
interface LinkDetection {
  // Direct link element
  target: HTMLAnchorElement;
  
  // Nested link detection
  parentTraversal: HTMLElement[];
  
  // Link identification
  isLinkElement: (element: HTMLElement) => element is HTMLAnchorElement;
}

Detection Examples:

// Direct link click
<a href="https://example.com">Click me</a>
// ✓ Detected: event.target is HTMLAnchorElement

// Nested element click
<a href="https://example.com">
  <span>Click me</span>
</a>
// ✓ Detected: traverses parent elements to find <a>

// Complex nesting
<a href="https://example.com">
  <strong>
    <em>Click me</em>
  </strong>
</a>
// ✓ Detected: traverses multiple parent levels

Link Selection

Optional link text selection when enableClickSelection is enabled.

/**
 * Link selection behavior when enableClickSelection is true
 * Selects the entire link text range before opening
 */
interface LinkSelection {
  /** Extend mark range to select entire link */
  extendMarkRange: (markName: string) => void;
  
  /** Selection happens before link navigation */
  selectionTiming: 'before-navigation';
}

Usage Examples:

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

// Enable link selection on click
const editor = new Editor({
  extensions: [
    Link.configure({
      openOnClick: true,
      enableClickSelection: true, // Selects link text before opening
    }),
  ],
});

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

Link Navigation

Configurable link opening behavior with target and security attributes.

Navigation Logic:

// 1. Extract link attributes from DOM or ProseMirror state
// 2. Priority: DOM attributes > ProseMirror mark attributes
// 3. Open link using window.open with proper target
// 4. Respect security attributes (rel="noopener")

Attribute Sources:

// DOM attributes (higher priority)
const href = linkElement.href;
const target = linkElement.target;

// ProseMirror mark attributes (fallback)
const attrs = getAttributes(view.state, 'link');
const href = attrs.href;
const target = attrs.target;

Advanced Click Configurations

Complex click handling configurations for different use cases.

Conditional Link Opening:

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

const editor = new Editor({
  extensions: [
    Link.configure({
      openOnClick: true,
      enableClickSelection: false,
      // Custom validation through isAllowedUri affects click behavior
      isAllowedUri: (url) => {
        // Only allow opening of safe URLs
        const safeDomains = ['example.com', 'tiptap.dev'];
        try {
          const urlObj = new URL(url);
          return safeDomains.includes(urlObj.hostname);
        } catch {
          return false;
        }
      },
    }),
  ],
});

Editor State-Aware Clicking:

// The click handler automatically respects editor state:

// When editor is not editable:
editor.setEditable(false);
// Links still clickable (navigation only)

// When editor is editable:
editor.setEditable(true);
// Links clickable with optional selection

Custom Click Handling:

// For custom click behavior, you can disable the built-in handler
// and implement your own:

const editor = new Editor({
  extensions: [
    Link.configure({
      openOnClick: false, // Disable built-in click handling
    }),
  ],
});

// Add custom click listener
editor.view.dom.addEventListener('click', (event) => {
  const target = event.target as HTMLElement;
  const link = target.closest('a');
  
  if (link) {
    event.preventDefault();
    // Custom logic here
    console.log('Link clicked:', link.href);
    
    // Optional: use editor commands
    if (confirmNavigation(link.href)) {
      window.open(link.href, '_blank');
    }
  }
});

Security Considerations

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

Security Features:

// 1. URL validation using configured isAllowedUri function
// 2. Proper target attribute handling
// 3. Security attributes preservation (rel="noopener")
// 4. XSS prevention through validation
// 5. Event sanitization

Safe Link Opening:

// The click handler ensures safe link opening:
window.open(href, target || '_blank');

// With security attributes:
// rel="noopener noreferrer" prevents window.opener access
// target="_blank" opens in new tab/window

Integration with Link Extension

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

Automatic Integration:

// When openOnClick is enabled in Link configuration:
const editor = new Editor({
  extensions: [
    Link.configure({
      openOnClick: true, // Automatically adds click handler plugin
      enableClickSelection: true,
    }),
  ],
});

// The Link extension automatically:
// 1. Creates click handler plugin with proper configuration
// 2. Passes editor reference and mark type
// 3. Configures selection behavior
// 4. Manages plugin lifecycle

Performance and UX

The click handler is optimized for performance and user experience.

Performance Features:

// 1. Efficient event filtering (left-click only)
// 2. Fast DOM traversal for link detection
// 3. Minimal attribute extraction
// 4. No unnecessary selection operations
// 5. Early returns for invalid states

UX Considerations:

// 1. Respects editor editability state
// 2. Optional link text selection for visual feedback
// 3. Proper cursor behavior after navigation
// 4. Security-conscious link opening
// 5. Consistent behavior across different link structures

Types

/** Configuration options for click handler plugin */
interface ClickHandlerOptions {
  type: MarkType;
  editor: Editor;
  enableClickSelection?: boolean;
}

/** Link element detection interface */
interface LinkElement extends HTMLAnchorElement {
  href: string;
  target?: string;
  rel?: string;
}

Install with Tessl CLI

npx tessl i tessl/npm-tiptap--extension-link

docs

autolink.md

click-handling.md

index.md

link-commands.md

link-configuration.md

paste-processing.md

url-validation.md

tile.json