Skip to content

fix(web): fast typing no longer scrambles text when type-to-focus kicks in - #13708

Closed
otavio wants to merge 1 commit into
pingdotgg:mainfrom
otavio:t3code/fix-input-autofocus-dictation
Closed

otavio wants to merge 1 commit into
pingdotgg:mainfrom
otavio:t3code/fix-input-autofocus-dictation

Conversation

@otavio

@otavio otavio commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

What Changed

focusAt in the Tiptap composer now focuses through ProseMirror's view.focus() instead of a bare view.dom.focus().

Why

When the composer is blurred, type-to-focus redirects the first keystroke into the draft and focuses the editor a frame later. A bare DOM focus leaves the native caret at offset 0. ProseMirror's state selection is already at the end (the controlled update set it while the editor was blurred), so the following setTextSelection changes nothing and nothing gets synced to the DOM. ProseMirror only resyncs the DOM caret in a 20ms timeout after focus. Voice dictation tools (here, whisrs over uinput at ~4ms per character) type faster than that, so keys landed ahead of the redirected text: dictating "Testing 1, 2, 3." produced ", 3.Testing 1, 2".

view.focus() does the same no-scroll focus and writes the state selection to the DOM synchronously, so the caret is at the end before the next key arrives.

Verified in a dev build by blurring the composer and firing a 1–4ms keydown burst (redirected keys first, then native insertion once the editor has focus):

  • Before: about half of runs scrambled (esting 1, 2, 3.T, 2, 3.Testing 1,, ...). Instrumentation showed ProseMirror's selection at the end while the DOM caret was at 0.
  • After: 14/14 runs correct, 9 of them crossing the redirect-to-native handoff.

UI Changes

None visible. Only the caret placement timing changes.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Done with Claude Opus 5.5 in Claude Code (via T3 Code).

Summary by CodeRabbit

  • Bug Fixes
    • Improved editor focus behavior so the native caret stays in sync with the current selection when the editor receives focus. This helps ensure the insertion point appears where expected when continuing to type.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XS 0-9 changed lines (additions + deletions). labels Sep 25, 2026
@otavio
otavio marked this pull request as ready for review September 25, 2026 22:01
@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

⚙️ Run configuration

Configuration used: Repository: pingdotgg/t3code/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 8ed276fd-fc1a-46bb-b842-fb5a9fec6388

📥 Commits

Reviewing files that changed from the base of the PR and between b2d602e and f6b231b.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: pingdotgg/t3code/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 58def72b-9f76-4003-b2bd-dbbcd4293b01

📥 Commits

Reviewing files that changed from the base of the PR and between ed809f7 and b2d602e.

📒 Files selected for processing (1)
  • apps/web/src/components/ComposerPromptEditorTiptap.tsx

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

The editor’s focusAt method now focuses the ProseMirror view instead of its DOM element directly.

Changes

Editor focus

Layer / File(s) Summary
Focus the ProseMirror view
apps/web/src/components/ComposerPromptEditorTiptap.tsx
focusAt now calls editor.view.focus() to focus the editor.

Priority: ➖ Normal

Estimated code review effort: 1 (Trivial) | ~5 minutes

Change: Bug fix

Suggested reviewers: juliusmarminge

Merge Risk: ⚪ Minimal · up to b2d60

The composer now synchronizes its selection through ProseMirror when focused, without changing viewport behavior. No concrete user impact remains, so this change is ready to merge.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 1 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main bug fix: preventing fast typing from scrambling text during type-to-focus.
Description check ✅ Passed The description explains the change, cause, solution, verification results, and lack of visible UI changes. It matches the required template and marks the focused checklist items.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

otavio added a commit to otavio/nix-config that referenced this pull request Sep 25, 2026
…oser

Dictating into a blurred composer scrambled the text: type-to-focus
redirected the first keystroke, but the editor's DOM caret stayed at
offset 0 until ProseMirror resynced it 20ms later, so fast dictation
keys landed ahead of it. Carry pingdotgg/t3code#13708, which focuses
through ProseMirror so the caret is placed synchronously.
…ks in

When the composer is blurred, the first keystroke is redirected into the draft and the editor
is focused a frame later. That focus used a bare DOM focus, which leaves the native caret at
the start of the editor until ProseMirror resyncs it about 20ms later. Voice dictation tools
such as whisrs type faster than that, so the next keys landed ahead of the redirected text
("Testing 1, 2, 3." became ", 3.Testing 1, 2").

Focus through ProseMirror's view.focus(), which writes the state selection to the DOM as it
focuses, so the caret is at the end before the next key arrives.

Copy link
Copy Markdown
Member

Note

This comment is posted by Julius' dot

The burst-test results describe the caret race, but no recording shows the type-to-focus handoff before and after. This timing change needs one under the verification requirement. I'm closing this pending a short clip showing the blurred composer, rapid input and resulting text. Attach it and request reconsideration.

@otavio
otavio deleted the t3code/fix-input-autofocus-dictation branch October 2, 2026 23:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XS 0-9 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants