From 85aabd7aace30f7cc795c0504c23b0fa2281f380 Mon Sep 17 00:00:00 2001 From: Jeff Agapitos <233853744+jeffa-block@users.noreply.github.com> Date: Thu, 19 Mar 2026 20:07:34 +1100 Subject: [PATCH 1/2] fix(ui): auto-focus chat input on Hub mount MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The textarea has autoFocus but it's unreliable across the async render chain (lazy App → Suspense → OnboardingGuard). Users had to press Tab ~12 times through nav buttons and session cards to reach the input. Add a useEffect with requestAnimationFrame that imperatively focuses the textarea after the Hub component mounts, so typing works immediately on launch. --- ui/desktop/src/components/Hub.tsx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/ui/desktop/src/components/Hub.tsx b/ui/desktop/src/components/Hub.tsx index b8d4774e7fed..d9b7395f9701 100644 --- a/ui/desktop/src/components/Hub.tsx +++ b/ui/desktop/src/components/Hub.tsx @@ -15,7 +15,7 @@ import { AppEvents } from '../constants/events'; * Hub (input submission) → Create Session → Pair (with session ID and initial message) */ -import { useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { SessionInsights } from './sessions/SessionsInsights'; import ChatInput from './ChatInput'; import { ChatState } from '../types/chatState'; @@ -39,6 +39,19 @@ export default function Hub({ const { extensionsList } = useConfig(); const [workingDir, setWorkingDir] = useState(getInitialWorkingDir()); const [isCreatingSession, setIsCreatingSession] = useState(false); + const inputRef = useRef(null); + + // Focus the chat input immediately after mount so users can start typing + // without tabbing through navigation and session elements first. + useEffect(() => { + // Use requestAnimationFrame to ensure the DOM has fully painted + // before focusing — more reliable than autoFocus across async + // render boundaries (Suspense, OnboardingGuard, etc.). + const frameId = requestAnimationFrame(() => { + inputRef.current?.focus(); + }); + return () => cancelAnimationFrame(frameId); + }, []); const handleSubmit = async (input: UserInput) => { const { msg: userMessage, images } = input; @@ -101,6 +114,7 @@ export default function Hub({ sessionCosts={undefined} toolCount={0} onWorkingDirChange={setWorkingDir} + inputRef={inputRef} /> From cb2244dd4a288712b8ca61de4bcef29c15de650e Mon Sep 17 00:00:00 2001 From: Douwe Osinga Date: Fri, 20 Mar 2026 09:29:05 -0400 Subject: [PATCH 2/2] fix(ui): collapse verbose comment to single line Signed-off-by: Douwe Osinga --- ui/desktop/src/components/Hub.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ui/desktop/src/components/Hub.tsx b/ui/desktop/src/components/Hub.tsx index d9b7395f9701..b7e971d1fadb 100644 --- a/ui/desktop/src/components/Hub.tsx +++ b/ui/desktop/src/components/Hub.tsx @@ -41,12 +41,8 @@ export default function Hub({ const [isCreatingSession, setIsCreatingSession] = useState(false); const inputRef = useRef(null); - // Focus the chat input immediately after mount so users can start typing - // without tabbing through navigation and session elements first. + // rAF is more reliable than autoFocus across async render boundaries (Suspense, OnboardingGuard, etc.) useEffect(() => { - // Use requestAnimationFrame to ensure the DOM has fully painted - // before focusing — more reliable than autoFocus across async - // render boundaries (Suspense, OnboardingGuard, etc.). const frameId = requestAnimationFrame(() => { inputRef.current?.focus(); });