Plate
PlateEditorsTemplates
GitHub16kGitHub
DiscordDiscord
    • Overview
    • Why This Fork
    • Examples
    • Installing Plite
    • Adding Event Handlers
    • Defining Custom Elements
    • Applying Custom Formatting
    • Executing Commands
    • Saving to a Database
    • Canonical Change Substrate
    • Improving Performance
    • Interfaces
    • Nodes
    • Locations
    • Transforms
    • Document Changes
    • Commands
    • Editor
    • Plugins
    • Rendering
    • Serializing
    • Normalizing
    • Using TypeScript
    • Roots
    • Document State
    • Editing Behavior
    • Selection And DOM
    • Clipboard And Paste
    • Decorations, annotations, and widgets
    • Schema
    • Anchor API
    • Location API
    • Path API
    • PointEntry API
    • Point API
    • Range API
    • Selection API
    • Location Types APIs
    • Span API
    • Editor
    • Element API
    • NodeEntry API
    • Node API
    • Node Types APIs
    • Text API
    • Debug Value Scrubbing
    • Transforms API
    • Plite DOM
    • History Editor API
    • History Plugin Setup
    • History
    • Plite History
    • Plite Hyperscript
    • Plite PaginationExperimental
    • Annotations
    • DOM Coverage Boundaries
    • Editable Component
    • External Text Views
    • Plite React Event Handling
    • Virtualized Rendering
    • Plite React Hooks
    • React Editor Setup
    • React Editor
    • Plite React
    • Plite Component
    • Plite Yjs
    • Plite
    • Migration
    • Contributing
    • FAQ
    • Resources

Plite DOM

PreviousNext

Use DOM, clipboard, hotkey, and coverage helpers outside React-owned rendering.

plitejs/dom is the DOM bridge for Plite editors. It owns DOM point/range conversion, selection conversion, clipboard formatting, hotkey helpers, contenteditable helpers, and DOM coverage metadata used by framework runtimes. React apps normally use these APIs through plitejs/react.

Usage

Framework runtimes usually call the DOM bridge through installed editor APIs.

editor.api.dom.focus();
editor.api.dom.clipboard.insertTextData(dataTransfer);
editor.api.dom.
Transforms APIHistory Editor API

On This Page

UsagePublic utility groupsDataTransfer formatsPublic type groupsDOM coverageInternal subpathRelated docs
Build your editor
Production-ready AI template and reusable components.
Get all-access
focus
();
editor.api.dom.clipboard.insertTextData(dataTransfer);

Use direct public imports from plitejs/dom for framework integration code that needs DOM bridge helpers without React.

import { DOMCoverage, Hotkeys, isDOMNode } from "plitejs/dom";
import { DOMCoverage, Hotkeys, isDOMNode } from "plitejs/dom";

Public utility groups

dom() installs the DOM bridge plugin on a core editor. DOMResolutionError is the thrown error type for failed assert-style DOM resolution.

DOMCoverage.create(editor) creates a view-local session for hidden, external, and virtualized same-root coverage metadata.

Hotkeys, isHotkey, and Key cover keyboard matching and keyboard names. TRIPLE_CLICK is the click count Plite uses for block-level triple-click handling.

Framework adapters can use DOMEditor, getEditorDOMRoot, createCompiledHotkeyMatcher, isGeckoDOMHost, and usesAppleDOMHotkeys for explicit host integration without importing private runtime modules.

DOM utilities include shadow-aware traversal, active element/window/selection lookups, DOM type guards, DOM point normalization, plain-text paste detection, tracked mutation detection, and DOM order checks:

import {
  closestShadowAware,
  containsShadowAware,
  getActiveElement,
  getDefaultView,
  getSelection,
  hasShadowRoot,
  isAfter,
  isBefore,
  isDOMElement,
  isDOMNode,
  isDOMSelection,
  isDOMText,
  isPlainTextOnlyPaste,
  isTrackedMutation,
  normalizeDOMPoint,
} from "plitejs/dom";
import {
  closestShadowAware,
  containsShadowAware,
  getActiveElement,
  getDefaultView,
  getSelection,
  hasShadowRoot,
  isAfter,
  isBefore,
  isDOMElement,
  isDOMNode,
  isDOMSelection,
  isDOMText,
  isPlainTextOnlyPaste,
  isTrackedMutation,
  normalizeDOMPoint,
} from "plitejs/dom";

Plite node marker helpers include getElements, getNodeDataAttributeKeys, keyToDataAttribute, isEditor, isElement, isLeaf, isNode, isString, isText, and isVoid.

Text-diff utilities include string diff normalization, merging, point/range projection, target-range calculation, and state verification:

import {
  applyStringDiff,
  mergeStringDiffs,
  normalizePoint,
  normalizeRange,
  normalizeStringDiff,
  targetRange,
  verifyDiffState,
} from "plitejs/dom";
import {
  applyStringDiff,
  mergeStringDiffs,
  normalizePoint,
  normalizeRange,
  normalizeStringDiff,
  targetRange,
  verifyDiffState,
} from "plitejs/dom";

CAN_USE_DOM guards SSR-only initialization. Mounted DOM adapters resolve browser behavior from their own root.

DataTransfer formats

dataTransferFormats installs schema-aware browser transfer representations as one named plugin. Each DataTransferFormat decodes or encodes one MIME type. Callbacks receive an immutable editor-state view; decode callbacks also receive an immutable snapshot of the incoming types, strings, and files.

import { ContentSlice, definePlugin, property, schema, target } from "plitejs";
import { dataTransferFormats } from "plitejs/dom";
 
const Bold = schema.textProperty("bold", property.boolean(), {
  target: target.type("paragraph"),
});
const DataAttribute = schema.elementProperty(
  schema.key.prefix("data_"),
  property.string(),
  { target: target.group("block") }
);
 
const editor = useEditor({
  plugins: [
    definePlugin("app-schema", {
      schema: { properties: [Bold, DataAttribute] },
    }),
    dataTransferFormats("app-html-transfer", [
      {
        mimeType: "text/html",
        key: "app-html",
        claims: [{ kind: "element", type: "paragraph" }, Bold, DataAttribute],
        decode: ({ data }) =>
          ContentSlice.closed([
            { type: "paragraph", children: [{ text: data }] },
          ]),
        encode: ({ slice }) => JSON.stringify(slice),
      },
    ]),
  ],
  initialValue,
});
import { ContentSlice, definePlugin, property, schema, target } from "plitejs";
import { dataTransferFormats } from "plitejs/dom";
 
const Bold = schema.textProperty("bold", property.boolean(), {
  target: target.type("paragraph"),
});
const DataAttribute = schema.elementProperty(
  schema.key.prefix("data_"),
  property.string(),
  { target: target.group("block") }
);
 
const editor = useEditor({
  plugins: [
    definePlugin
















decode returns a ContentSlice, or null to delegate the payload to the next format. encode returns a string, or null to leave its MIME type to the next encoder. accept returns false to skip the format before decoding. Every declaration needs decode, encode, or both.

Decoded slices keep their open edge depths and detached roots. Use ContentSlice.closed(content) for a closed fragment or ContentSlice.fromJSON(payload) for validated open data. Insertion fits the slice against the actual target. An unfit result delegates without publishing a partial write.

Decode callbacks receive { data, mimeType, report, snapshot, state }. Encode callbacks receive { mimeType, slice, state }. They do not receive the editor, a live DataTransfer, a fitter, or a transaction. Formats run in reverse configuration order, so the last configured format gets the first opportunity for its MIME type. The built-in plain-text decoder always runs last.

Ownership claims compile against the candidate editor schema before a plugin revision publishes. { kind: "schema" } owns the complete schema. Element claims use stable element types. Property claims reuse the same schema.elementProperty(...) or schema.textProperty(...) declaration in the schema contribution and format. Matching is structural, not object-identity based. The compiler derives one stable identity from the declaration's placement, key, and target, so equal keys with disjoint targets remain independently claimable. Key-only claims and raw compiled IDs are not accepted. Duplicate keys, unknown declarations, and overlapping claims in the same MIME type and direction reject the complete configuration revision. Decode and encode ownership are independent.

Return null for foreign or malformed input; clipboard data is untrusted and bad input is not a bug. Exceptions from accept, decode, or encode go to the editor's lifecycleErrorSink with source: "data-transfer-format", the format key, mimeType, pluginName, and phase ("accept", "decode", or "encode"); negotiation then continues with the next format, so a failing format cannot block paste or copy. A decoded value that is not a valid ContentSlice, or an encoded value that is neither a string nor null, is reported the same way. During accept or decode, call report({ impact: "lossy", message: "Unsupported content was omitted." }) to report conversion loss. impact accepts "lossless" or "lossy". Mounted paste delivers conversion diagnostics through Editable.onPasteResult. Add a mapping or a format for content the current formats cannot represent.

Framework clipboard writers call writeDataTransferFragment(editor, data, slice) to run registered encoders into a setData-compatible sink. Each MIME type is written once: the first encoder that returns a string wins. The function returns the written MIME types. Applications normally use editor.api.dom.clipboard.writeSelection(dataTransfer), which writes the native Plite payload and registered MIME representations together.

Public type groups

DOM bridge types include DOMApi, DOMClipboardApi, DOMClipboardInsertDataHandler, DOMEditorOptions, ScrollIntoViewOptions, and ScrollIntoViewTarget.

DOM coverage types include DOMCoverageSession, DOMCoverageBoundary, DOMCoverageSelectionPolicy, DOMCoveragePointResult, and DOMCoverageDOMRangeResult. Use these when a framework layer needs to describe hidden or virtualized same-root content.

DOM primitive type names include DOMNode, DOMElement, DOMText, DOMPoint, DOMRange, DOMStaticRange, and DOMSelection.

DataTransfer types include DataTransferFormat, DataTransferDecodeContext, DataTransferEncodeContext, DataTransferSnapshot, DataTransferSchemaClaim, and DataTransferFormatPhase.

Hotkey and diff helper types include HotkeySpec, HotkeyPlatform, HotkeyMatchOptions, KeyboardEventLike, StringDiff, and TextDiff.

DOM coverage

DOM coverage boundaries model same-root content whose DOM is hidden or virtualized. They keep selection, copy, find, and Plite-to-DOM conversion tied to explicit policies instead of assuming every document node is mounted.

React applications configure coverage through slots.contentBoundary or slots.externalText. Each Editable owns its session and releases it on unmount.

Framework integrations create one session per mounted view:

import { DOMCoverage } from "plitejs/dom";
 
const coverage = DOMCoverage.create(editor);
const dispose = coverage.registerBoundary(boundary);
 
dispose();
coverage.destroy();
import { DOMCoverage } from "plitejs/dom";
 
const coverage = DOMCoverage.create(editor);
const dispose = coverage.registerBoundary(boundary);
 
dispose();
coverage.destroy();

Call query, conversion, and materialization methods on that session. Do not share registrations between views of the same editor. A registration's disposer cannot remove a later replacement with the same boundary id.

Internal subpath

The /internal package subpath is reserved for sibling Plite packages in this repo. Applications, plugin libraries, and framework adapters outside this workspace should use the root plitejs/dom export.

Related docs

  • React Editor
  • Editable Component
  • Clipboard And Paste
  • DOM Coverage Boundaries
  • Event Handling
(
"app-schema"
, {
schema: { properties: [Bold, DataAttribute] },
}),
dataTransferFormats("app-html-transfer", [
{
mimeType: "text/html",
key: "app-html",
claims: [{ kind: "element", type: "paragraph" }, Bold, DataAttribute],
decode: ({ data }) =>
ContentSlice.closed([
{ type: "paragraph", children: [{ text: data }] },
]),
encode: ({ slice }) => JSON.stringify(slice),
},
]),
],
initialValue,
});