Stop the editor stealing focus from the sidebar - #202
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 everytrix-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 firestrix-changeper 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-attributesJSON 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
selectionchangewhose 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 raisesselectionchangeon 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. CallingstopEditingAttachment()there does not work — it runs the same teardown and steals focus just as thoroughly.focusoutrather thantrix-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:
Green in all four combinations.
vitest11/11,tscandeslintclean.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