[BUG] Desktop: first click on a plugin pane button only moves focus; the button needs a second click
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
In the Claude Code desktop app (Code tab), a plugin pane opened with $.ui.open({ id, title, rows }) draws Buttons from a ui.render hook.
When the pane does not hold the keyboard focus (e.g. after any turn, when the focus goes back to the prompt), the first click on a button raises ui.focus onto that button but no ui.press. Only a second click presses it. Every button in the pane behaves this way. Built-in panes don't have this problem.
Opening the pane with focus: true makes the first click work, but only until the next turn takes the focus back to the prompt.
- Claude Code desktop app (Code tab), Windows 11 Pro 10.0.26200.
- Suggestion: have a pointer click on an unfocused pane both move the focus and raise
ui.press, or expose the input kind (pointer vs keyboard) inUiFocusOrigin.
What Should Happen?
The ButtonProps docs say "a click, a hotkey, ... raises ui.press". A pointer click should press the button whether or not the pane holds the focus, as it does in built-in panes.
Error Messages/Logs
# Hook events logged by the plugin (ui.focus / ui.press hooks on that pane)
# Pane without the focus, one click:
ui.focus element=rc4 origin=person
(no ui.press)
# Second click:
ui.press element=rc4 -> onPress runs (2ms)
# Pane freshly opened with open({ focus: true }), one click:
ui.focus element=r4 origin=person
ui.press element=r4 -> onPress runs (2ms)
Steps to Reproduce
- A plugin with a pane:
on('ui.render', { component: 'Pane', requestId: 'x' }, ...)returning a<Button onPress={...} />, opened with$.ui.open({ id: 'x', title: 'x', rows: 30 }). - Add hooks that log
ui.focus(matcher{ requestId: 'x' }) andui.press(matcher{ plugin: '<name>' }). - Open the pane, then send any prompt so a turn runs (the focus goes back to the prompt).
- Click the button once: only
ui.focusis raised, nothing happens. - Click it again:
ui.pressis raised andonPressruns.
A plugin can't work around it: UiFocusOrigin is { kind: 'person' } for a click, Tab and arrows alike, so pressing a button from ui.focus would also fire it on Tab (dangerous for a destructive button).
Claude Model
_No response_
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.289 (Claude Code)
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
PowerShell
Additional Information
- Claude Code desktop app (Code tab), Windows 11 Pro 10.0.26200.
- Suggestion: have a pointer click on an unfocused pane both move the focus and raise
ui.press, or expose the input kind (pointer vs keyboard) inUiFocusOrigin.
<img width="870" height="449" alt="Image" src="https://github.com/user-attachments/assets/af7c6abb-3436-427c-af21-e1abe7bccbfa" />
<img width="406" height="119" alt="Image" src="https://github.com/user-attachments/assets/f53cc4e3-736b-4ee0-b46d-ebb1c0a811e7" />
<img width="899" height="686" alt="Image" src="https://github.com/user-attachments/assets/4f3f9e5b-cbc6-4d7c-9f00-2f8fffd03001" />
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Same on macOS.
$.ui.open({ id, title }), nofocus)Every button in the pane needs two clicks, including a "back" button drawn after the first press already focused the pane. Logged from
ui.focus/ui.presshooks in a separate mod:86745ms focus Pane/list element=item:1 origin={"kind":"person"}
87820ms press my-mod/Pane element=item:1 surface=desktop
89159ms focus Pane/list element=back origin={"kind":"person"}
90256ms press my-mod/Pane element=back surface=desktop
The first click of each pair raises only
ui.focus; the second raisesui.pressandonPressruns normally. Possibly related: #99211.Also on macOS: Claude desktop app 2.19675.0, Code tab, Claude Code 2.1.286 (session), macOS 26.6.2 (25G83).
Logging
ui.focus,ui.pressand each Pane draw (withisFocused) points at the click being lost to a re-render:``
`16:05:52.928 draw Pane focused=true
16:05:54.934 draw Pane focused=true ← click 1
16:05:54.934 focus element=view-board origin=person
16:05:55.779 press element=view-board ← click 2
$.ui.focus({ requestId, key })` works): no ring move, no redraw.If that redraw replaces the Button's DOM node between mousedown and click, the click never lands. That would also explain why a Button **already holding the ring presses in one click** (moving it there first with
isFocusedstaystruethroughout, and every Button other than the ring's holder still needs two clicks.focused=false. That is why a "back" button drawn by the first press looks like it needs two clicks too.Same on macOS (26.5.2), desktop app Code tab, Claude Code 2.1.293. Two things to add:
ui.focusreaches the hooks, the pane is already focused ($.ui.panes()reportsisFocused: trueand the pane has redrawn withisFocused: true), so "was the pane focused before this move?" can't be read from the hook.Log from the hooks (
ui.focus/ui.press/ui.toastand the pane'sui.render), pane unfocused, two clicks on the same Button:A pointer-vs-keyboard field on
UiFocusOrigin, or a click that both focuses and presses, would fix it.