Install

Works with Drupal: ^11

Using Composer to manage Drupal site dependencies

Alternative installation files

Download tar.gz 24.07 KB
MD5: 0226e66208b2cccde651c082894ce490
SHA-1: 2788e33cf56afc7eab57b1a834f6e4e06d68ee9e
SHA-256: 819746f9d52c511b7ee615fcc468530a26e33d9b24fd42469d469d3bbe3282aa
Download zip 28.98 KB
MD5: 46dadc6379eaf72300ba81e1c80926d4
SHA-1: 85b40540254277fa3ead2162255b33be514b9db8
SHA-256: 00c4b3274d675b02b6cdb84c980b9ff6c2ad59ade4aa625ff0f2b337cd96219a

Release notes

Microedit lets authorized users highlight a word, phrase, or sentence in a node's body and edit its whole containing text block in a CKEditor 5 modal. It keeps the original block's inline HTML (<strong>, <em>, links, etc.) intact. The originally highlighted phrase is shown with the same pale-yellow background used for the post-save page highlight. The editor highlight uses the browser's CSS Custom Highlight API and is never inserted into saved HTML.

Requirements

  • Drupal 11.
  • The node body field with a text format that uses CKEditor 5.

Workflow

  1. Select part of a paragraph, heading or another supported text block on a node's canonical page. Triple-clicking a paragraph also works.
  2. The full block to be edited receives a temporary light-grey text background while the Edit button is visible. The preview disappears when you clear the selection or open the dialog. Click the small Edit button. The whole block opens in the modal, with existing markup preserved.
  3. The original selected passage is temporarily highlighted pale yellow in the editor; the highlight is not stored and disappears when you start editing.
  4. Make changes, including new paragraphs and allowed block elements, and click Save text.
  5. The node is saved with a new revision, the page reloads, and the module attempts to scroll to and highlight the changed text.

Technical behavior

  • Supported content blocks include p, h1–h6, blockquote, pre, leaf div elements, simple li, dt, dd, and figcaption elements. A div containing paragraphs is treated as a structural container, not the edit target. Selections crossing two different editable blocks are rejected.
  • Before showing the Edit button, the client looks up the selected text and a sufficiently long adjacent literal text fragment only in the unfiltered stored body blocks. It does not compare rendered block contents, use rendered block positions, or trust HTML IDs or source-index attributes.
  • The client sends the chosen stored block tag/index/normalized prefix/suffix/length. The server independently finds that same block in the unfiltered body value and verifies the selected phrase occurs in the stored block. Ambiguous or weak matches are rejected.
  • A changed body since the dialog opened is rejected via SHA-256 comparison. Server-side edit permissions and text-format access are rechecked during submission.
  • Replacement HTML is parsed and takes the place of the complete original block, not just the selected characters. This avoids splitting nested inline elements. For simple list items, the surrounding list and original <li> attributes remain intact. Edits to structurally complicated nested tables/lists are intentionally limited.
  • A separate CSS Custom Highlight (::highlight(microedit-target-block)) previews the entire target block on the page with a light-grey background. It is removed when the selection is cleared or the dialog opens, and never changes saved HTML.
  • A CSS Custom Highlight (::highlight(microedit-editor-selection)) temporarily marks the original selection within CKEditor's editable DOM. It does not add spans, marks, CKEditor model attributes, or persisted HTML. In browsers without CSS Custom Highlight API, editing still works but the temporary marking may be absent.
  • CKEditor's existing format defines which HTML constructs can be edited and retained. Save/reload/scroll, modal focus/Escape, and dialog CSS classes are retained. The outer modal has class .microedit-modal and the inner form .microedit-dialog.

Caveats

  • The module targets only the single-value body field on canonical node pages and requires CKEditor 5 for that text format.
  • Drupal text filters may substantially change rendered markup or text; when a block cannot be mapped safely to stored HTML, editing is rejected.
  • DOMDocument serialization may normalize HTML entities, whitespace, and element casing across the saved body. Test with embedded media and site-specific markup.
  • The yellow highlight is best effort if CKEditor transforms the originally selected text (e.g., whitespace normalization). It is cosmetic only.

CKEditor link visibility

The module scopes link-color styling to the CKEditor editing surface inside the Microedit modal. It makes existing links visibly blue and underlined without changing their saved HTML or the normal site theme.

Stored-body-only selection guard

The original body.value from the node is the only source used to build candidate
editable blocks. No markers or IDs are injected into the text-filter pipeline.
The browser reads the text the user actually selected and nearby contiguous
text as a lookup key into that raw value. It never identifies a source block by
comparing the entire rendered paragraph to a source paragraph. Shortcodes,
BBCode and embedded directives remain part of the raw block loaded into CKEditor.

For safety, blocks with no unique raw-source match are not editable. A minimum
surrounding context is required for long raw paragraphs to avoid allowing a
single common word inside generated content. Some very short or heavily
transformed selections will therefore not offer editing.

Provenance limitation: a browser selection necessarily originates from the
rendered DOM. If a filter generates text that is indistinguishable from a
literal sequence in the original body, raw-string matching alone cannot prove
which node it came from. Absolute exclusion of such generated text requires
integration with the text filter or a separately rendered raw editing surface.

Console diagnostics

Console logging is off by default. To enable selection-decision logs,
set const LOG_DEBUG = true; near the top of js/microedit.js
and clear Drupal caches. Set it back to false to disable the logs.
The manually invoked microeditInspectLinks() diagnostic remains
available if you explicitly call it from the console.

Created by: steven snedker
Created on: 9 Nov 2026 at 06:38 UTC
Last updated: 9 Nov 2026 at 06:38 UTC
New features

Other releases