Clipboard And Paste

PreviousNext

Route copy, paste, drop, and fragment insertion through Plite's editor, DOM, and extension layers.

Clipboard work crosses browser events, Plite fragments, transactions, DOM coverage, and browser proof. Use this page to decide whether a paste, copy, or drop policy belongs in Editable, an extension, editor.api.clipboard, or a fragment transform.

Choose The Right Surface

Paste bugs usually come from mixing browser event ownership with model insertion ownership.

NeedStart withOwner
One editor instance needs a local paste/drop hookEditable onPaste or onDrop@platejs/plite-react
A reusable package owns paste/drop import policyextension clipboard.insertData@platejs/plite
Framework code needs to import a DataTransfereditor.api.clipboard.insertData(data)@platejs/plite-dom through @platejs/plite-react
Structural fragment insertion is already decodedtx.fragment.insert(fragment, options?)@platejs/plite
Copy or drag must include hidden model contentDOM coverage copyPolicy plus model-backed clipboard data@platejs/plite-dom and @platejs/plite-react
The claim depends on real browser clipboard behavior@platejs/browser clipboard helpers@platejs/browser

Use Editable for local event interception. Use extension clipboard policy when the behavior should apply to native paste, drop, browser tests, and every React surface that installs the extension.

Runtime Pipeline

Clipboard data enters Plite through explicit layers.

StageWhat happensOwner
Browser eventThe browser produces paste, cut, copy, dragstart, or drop with a DataTransfer.Browser
Editable handlerApp handlers can handle the event or let Plite continue.@platejs/plite-react
Clipboard middlewareExtension clipboard.insertData handlers can claim the payload.@platejs/plite
DOM clipboard importPlite reads the configured internal Plite fragment key, then falls back to text.@platejs/plite-dom
TransactionThe decoded content is inserted through tx.fragment, tx.text, or another extension-owned transform.@platejs/plite
Commit and renderPlite publishes one change; React renders and repairs selection.@platejs/plite and @platejs/plite-react
ProofBrowser tests assert model content, DOM/native selection where needed, focus, clipboard payload, and follow-up typing.@platejs/browser

Do not close a paste bug with only a model assertion when the failure was in the browser event, DOM clipboard payload, native selection, or follow-up typing.

Extension Clipboard Policy

Use clipboard.insertData when a feature owns a reusable import rule.

import { defineEditorExtension } from "@platejs/plite";
 
const pasteTodoPrefix = defineEditorExtension({
  name: "paste-todo-prefix",
  clipboard: {
    insertData(data, { next, tx }) {
      const text = data.getData("text/plain");
 
      if (!text.startsWith("todo:")) {
        return next();
      }
 
      tx.text.insert(text.slice("todo:".length).trim());
 
      return true;
    },
  },
});
import { defineEditorExtension } from "@platejs/plite";
 
const pasteTodoPrefix = defineEditorExtension({
  name: "paste-todo-prefix",
  clipboard: {
    insertData(data, { next, tx }) {
      const text = data.getData("text/plain");
 
      if (!text.startsWith("todo:")) {
        return next();
      }
 
      tx.text.insert(text.slice("todo:".length).trim());
 
      return true;
    },
  },
});

The handler receives the transaction owned by clipboard ingress. Return true when the extension handled the payload. Return next() when Plite should keep running the internal fragment and plain-text import path in that transaction.

Use this for package-owned import rules such as custom inline syntax, pasted URLs, product fragments, and table-specific paste policy. Do not put those rules in Plite core unless the rule is part of Plite's model contract.

DOM Clipboard API

React editors expose DOM clipboard helpers through editor.api.clipboard.

editor.api.clipboard.insertData(dataTransfer);
editor.api.clipboard.insertFragmentData(dataTransfer);
editor.api.clipboard.insertTextData(dataTransfer);
editor.api.clipboard.writeSelection(dataTransfer);
editor.api.clipboard.insertData(dataTransfer);
editor.api.clipboard.insertFragmentData(dataTransfer);
editor.api.clipboard.insertTextData(dataTransfer);
editor.api.clipboard.writeSelection(dataTransfer);

Use these APIs from framework bridges, tests, or low-level event code that already has a DataTransfer. insertData owns a transaction when called directly and joins the active transaction when framework code already opened one. Clipboard middleware mutates through the supplied tx.

Plite writes plain text, HTML, and an internal Plite fragment payload. The fragment payload uses application/${clipboardFormatKey}, so editors with different keys do not blindly import each other's internal JSON.

Fragment Insertion

Fragments are Plite node slices. Insert them with tx.fragment.insert(...) when the payload is already decoded.

editor.update((tx) => {
  tx.fragment.insert([
    {
      type: "paragraph",
      children: [{ text: "Pasted paragraph" }],
    },
  ]);
});
editor.update((tx) => {
  tx.fragment.insert([
    {
      type: "paragraph",
      children: [{ text: "Pasted paragraph" }],
    },
  ]);
});

Core fragment insertion is structural. Grid-aware table paste, spreadsheet mapping, and product-specific merge rules belong in the table or product extension that understands those structures.

Hidden And Projected Content

Copy and drag can involve model content whose DOM is hidden, staged, or virtualized. DOM coverage boundaries decide whether hidden content participates in copy, find, and selection conversion.

Use DOM Coverage Boundaries for copyPolicy, findPolicy, selectionPolicy, and materialization behavior. Use Selection And DOM when a copy or paste bug also depends on caret position or native selection repair.

Browser Proof

Clipboard proof should name the layer that can fail.

ClaimUseful proof
The model inserted the right contentmodel text, fragment, operations, and selection
The DOM payload was imported correctlybrowser clipboard helper or dispatched DataTransfer
Hidden content copied correctlycopied plain text, HTML, Plite fragment, and DOM coverage policy
Selection survived pastemodel selection, DOM/native selection where observable, and follow-up typing
A feature owns paste policyfocused extension test plus browser paste smoke

Use Browser for clipboard helpers and Editing Behavior for the full event-to-commit pipeline.