Repository navigation
[Bug]: Typing with the composer unfocused no longer goes to the composer #13403
Description
Activity
Confirmed on
mainat b2b43be. Both causes match the current web/desktop chat UI. Mobile uses a separate composer and is not on this path.Closed header menu always blocks type-to-focus and launcher letters.
#12453renders the chat header actionsMenuPopupwithkeepMounted(apps/web/src/components/chat/ChatHeader.tsx). Base UI’s menu portal stays in the DOM whenkeepMountedis set, and a closed popup carriesdata-closedrather thandata-open. That popup is mounted for every thread, including wide layouts where the trigger is hidden.shouldRedirectInputToComposerinapps/web/src/components/ChatView.tsxbails whendocument.querySelectorfinds any[data-slot="menu-popup"]. The same unguarded list isLAUNCHER_SHORTCUT_BLOCKING_LAYERSinapps/web/src/components/RightPanelTabs.tsx, which is why the launcher letters (T, B, F, M, …) never fire. Dialog, alert-dialog, command-dialog, sheet, and mobile sidebar entries in the ChatView selector already require:is([data-open],[data-ending-style]). The menu, select, popover, combobox, and autocomplete entries do not. The timeline keyboard-scroll handler inChatViewuses that same selector, so it is gated by the closed menu as well.Other menus unmount when closed. The header menu is the one that makes the check succeed on every thread. An actually open popup, including one animating out (
data-ending-style), should keep blocking.After that gate is fixed, the first typed character and the caret disagree. This path has been in
ComposerPromptEditorTiptapsince#12160. The first key goes throughinsertTextAtEnd→applyPromptReplacement, which schedulesfocusAton the next frame. The controlled layout effect runs first and callssetTextSelectionwhile the editor is unfocused. In prosemirror-view 1.42.3,selectionToDOMreturns immediately unless the view has focus, so the ProseMirror selection is stored at the end and the DOM caret is not moved.focusAtthen callseditor.view.dom.focus()rather thanview.focus()(which would sync the DOM selection after focusing). The followingsetTextSelectiontargets the selection already stored, andupdateStateInnerskipsselectionToDOMwhen the document and selection are unchanged. The browser caret stays at the start, so the next key lands in front of the first (hi→ih). A single character still looks right, because only the second key is a native insert.Workaround is unchanged: click the composer before typing.
- addedacceptedfeature request acceptedfeature request acceptedbugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.via-triageFiled through npx t3 triageFiled through npx t3 triage
on Sep 24, 2026
Before submitting
Area
apps/web
Steps to reproduce
hi.Expected behavior
The composer takes focus and contains
hi(type-to-focus).Actual behavior
Nothing happens. Keys are dropped. The right panel launcher's letter shortcuts (T, B, F, M…) are dead for the same reason.
There are two causes:
MenuPopupkeepMounted, so a closed[data-slot="menu-popup"]now stays in the DOM on every thread.shouldRedirectInputToComposerinChatView.tsxand the launcher's capture handler inRightPanelTabs.tsxboth bail ondocument.querySelector(<popup slots>)without checking whether the popup is open, so they always bail. The dialog entries in the same selector already use:is([data-open],[data-ending-style]); the menu/select/popover/combobox/autocomplete entries don't.hibecomesih. The first key goes throughinsertTextAtEnd. The controlled layout effect inComposerPromptEditorTiptapstores the ProseMirror selection after it while the editor is unfocused. ThenfocusAtcallseditor.view.dom.focus(), which leaves the browser caret at the start.setTextSelectionto the already-stored position does nothing, so the DOM caret never moves and the next key lands before the first. This has been there since feat(web): enable rich text composer by default #12160.Impact
Major degradation or frequent failure
Version or commit
mainat b2b43be (desktop 0.0.42 nightly shows it too)Environment
macOS 26, desktop app and web (Chromium)
Workaround
Click the composer before typing.