Skip to content

Stop the editor stealing focus from the sidebar - #202

Merged
ssavutu merged 1 commit into
mainfrom
fix/editor-caption-focus
Aug 7, 2026
Merged

Stop the editor stealing focus from the sidebar#202
ssavutu merged 1 commit into
mainfrom
fix/editor-caption-focus

Conversation

@ssavutu

@ssavutu ssavutu commented Aug 7, 2026

Copy link
Copy Markdown
Member

Editing an image caption and then typing in the author or section search box put the first letter in the search box and the rest back in the article.

Three separate paths lead there. All of them end the same way: Trix re-renders and restores its own selection, and the browser's focus goes with it.

1. We were mutating Trix's DOM on every keystroke

The alignment effect wrote CSS classes onto the <figure> elements inside the contenteditable on every trix-change. Trix's MutationObserver treats that as a foreign mutation: it re-parses the document, re-renders it, and restores the selection. Editing a caption fires trix-change per keystroke, so each one queued a re-parse; click into the sidebar while one is in flight and the pending restore lands a keystroke later.

Alignment now comes from CSS attribute selectors on the data-trix-attributes JSON Trix writes itself, so nothing of ours touches the contenteditable. This also fixes the editor stealing focus on page load for articles with aligned images.

2. A stale selection left behind when focus leaves

Trix decides an attachment is no longer being edited by watching for a selectionchange whose range isn't the attachment's own. While an image sat in that state the check stayed armed after the author had clicked away — and Firefox raises selectionchange on the document when you type in a plain <input> (Chrome raises it on the input). So the first letter typed into the sidebar fired the teardown, whose re-render took the focus back. This is the path that reproduces the reported symptom letter-for-letter.

Fixed by clearing the stale DOM selection on focusout, which leaves Trix reading no range instead of a stale one. Calling stopEditingAttachment() there does not work — it runs the same teardown and steals focus just as thoroughly.

focusout rather than trix-blur: while a caption is open the focus is on the caption field, so the editor element never blurs.

3. The first click into a caption did nothing

Trix opens the caption field on mousedown and focuses it a tick later. In between, the selection settles outside the attachment's range, Trix stops editing the attachment, and the deferred focus() lands on an element no longer in the document. The caption took a second click to enter, and the first click had quietly dropped focus out of the editor.

Fixed by re-opening the caption once after the click settles. Trix ignores a request to edit the attachment it is already editing, so it is a no-op when nothing broke; a click elsewhere in the window cancels the pending restore.

Testing

Driven in a real browser against the article editor with a stubbed API — Chromium and Firefox, against both plain and legacy WordPress-aligned article bodies:

  • single-click caption entry, and the typed text committing to the caption
  • typing in the sidebar search after a caption edit (the reported bug)
  • clicking from a caption straight into the body, and into the sidebar
  • image selection and the attachment toolbar
  • body typing before and after a trip out to the sidebar
  • the toolbar tracking a selection made after returning from the sidebar

Green in all four combinations. vitest 11/11, tsc and eslint clean.

Not changed

The blue outline on a selected image (.attachment--selected) never shows, because Trix's re-render drops the class we add — the same "we mutate Trix's DOM" pattern. Pre-existing and identical before and after this change, and the image still reads as selected via Trix's own toolbar and caption highlight. Left for a follow-up.

🤖 Generated with Claude Code

Editing an image caption and then typing in the author or section search
box put the first letter in the search box and the rest back in the
article. Three separate paths led there; all of them end in Trix
re-rendering and restoring its own selection, which takes the browser's
focus with it.

Alignment is no longer written onto the live figure as a class. Anything
we put into the editor's DOM is a foreign mutation to Trix's
MutationObserver: it re-parses, re-renders and restores the selection.
Doing that on every trix-change -- so on every keystroke in a caption --
made the editor un-leavable while an image was selected. TrixEditor.css
now keys off the data-trix-attributes JSON Trix writes itself, so nothing
of ours touches the contenteditable.

A stale selection is dropped when focus leaves the editor. Trix decides
an attachment is no longer being edited by watching for a selectionchange
whose range is not the attachment's own; while an image sat in that state
the check stayed armed after the author had clicked away, and Firefox
raises selectionchange on the document for typing in a plain <input>
(Chrome raises it on the input). The first letter typed into the sidebar
fired it, and the teardown's re-render took the focus back. Clearing the
selection leaves Trix reading no range rather than a stale one. Asking it
to stop editing the attachment instead does not work -- that runs the
same teardown and steals the focus just as thoroughly.

The caption is re-opened after a click that Trix tore down. Trix opens
the caption field on mousedown and focuses it a tick later; in between,
the selection settles outside the attachment's range, Trix stops editing,
and the deferred focus lands on an element no longer in the document. So
the first click on a caption appeared to do nothing, it took a second
click to type in one, and the first click had quietly dropped focus out
of the editor.

Verified in Chromium and Firefox, against both plain and legacy
WordPress-aligned article bodies: single-click caption entry, caption
text committing, typing in the sidebar after a caption edit, clicking
from a caption to the body and to the sidebar, image selection, body
typing before and after a trip to the sidebar, and the toolbar tracking
a selection made after one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ssavutu
ssavutu merged commit 5e4bb53 into main Aug 7, 2026
6 checks passed
@ssavutu
ssavutu deleted the fix/editor-caption-focus branch August 7, 2026 02:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant