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.
| Need | Start with | Owner |
|---|---|---|
| One editor instance needs a local paste/drop hook | Editable onPaste or onDrop | @platejs/plite-react |
| A reusable package owns paste/drop import policy | extension clipboard.insertData | @platejs/plite |
Framework code needs to import a DataTransfer | editor.api.clipboard.insertData(data) | @platejs/plite-dom through @platejs/plite-react |
| Structural fragment insertion is already decoded | tx.fragment.insert(fragment, options?) | @platejs/plite |
| Copy or drag must include hidden model content | DOM 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.
| Stage | What happens | Owner |
|---|---|---|
| Browser event | The browser produces paste, cut, copy, dragstart, or drop with a DataTransfer. | Browser |
| Editable handler | App handlers can handle the event or let Plite continue. | @platejs/plite-react |
| Clipboard middleware | Extension clipboard.insertData handlers can claim the payload. | @platejs/plite |
| DOM clipboard import | Plite reads the configured internal Plite fragment key, then falls back to text. | @platejs/plite-dom |
| Transaction | The decoded content is inserted through tx.fragment, tx.text, or another extension-owned transform. | @platejs/plite |
| Commit and render | Plite publishes one change; React renders and repairs selection. | @platejs/plite and @platejs/plite-react |
| Proof | Browser 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.
| Claim | Useful proof |
|---|---|
| The model inserted the right content | model text, fragment, operations, and selection |
| The DOM payload was imported correctly | browser clipboard helper or dispatched DataTransfer |
| Hidden content copied correctly | copied plain text, HTML, Plite fragment, and DOM coverage policy |
| Selection survived paste | model selection, DOM/native selection where observable, and follow-up typing |
| A feature owns paste policy | focused extension test plus browser paste smoke |
Use Browser for clipboard helpers and Editing Behavior for the full event-to-commit pipeline.