When a text selection in Obsidian’s Live Preview spans an embed that you’ve made, you can visualise that selection with a minimal CodeMirror 6 plugin that toggles a CSS class on the embed’s root element.
Minimal logic (selection overlap + CSS toggle)
Assumptions:
- Your embeds are CM6 widgets that render a root element like
<div class="my-embed" data-embed-id="..."> - You already have a
DecorationSetfield for those widgets (calledyourEmbedsFieldbelow)
Copyimport { EditorView, ViewPlugin, ViewUpdate } from "@codemirror/view"; import type { DecorationSet } from "@codemirror/view"; // Returns true if a selection range crosses the widget range function selectionSpansWidget( selFrom: number, selTo: number, widgetFrom: number, widgetTo: number ): boolean { if (selFrom === selTo) return false; // ignore cursor-only return ( (selFrom < widgetFrom && selTo > widgetTo) || // wraps widget (selFrom < widgetFrom && selTo > widgetFrom) || // ends inside (selFrom < widgetTo && selTo > widgetTo) // starts inside ); } // Given your existing decoration field of embed widgets: declare const yourEmbedsField: any; // StateField<DecorationSet> export const highlightSelectionAcrossEmbeds = ViewPlugin.fromClass(class { constructor(private view: EditorView) { this.updateDom(); } update(u: ViewUpdate) { if (u.selectionSet || u.docChanged || u.viewportChanged) { this.updateDom(); } } updateDom() { const embeds: DecorationSet | undefined = this.view.state.field(yourEmbedsField, false); if (!embeds) return; // Reset all this.view.dom.querySelectorAll<HTMLElement>(".my-embed") .forEach(el => el.classList.remove("my-embed--highlighted")); // For each widget, check if the current selection spans it const it = embeds.iter(); while (it.value) { const widget = it.value.spec?.widget as { id?: string } | undefined; if (widget?.id) { const from = it.from, to = it.to; const overlaps = this.view.state.selection.ranges.some(r => selectionSpansWidget(r.from, r.to, from, to) ); if (overlaps) { const el = this.view.dom.querySelector<HTMLElement>(`.my-embed[data-embed-id="${widget.id}"]`); if (el) el.classList.add("my-embed--highlighted"); } } it.next(); } } });
Minimal CSS
.my-embed {
position: relative;
}
.my-embed--highlighted {
background-color: #FF0000
}
That’s It!
Detect if the current selection spans a widget’s range, and toggle a highlight class on the embed’s root element that you adjust in CSS.
