From 443ce4c22215e3bb73fedbc0ea1b6093aca933e8 Mon Sep 17 00:00:00 2001
From: badcuban <108198679+badcuban@users.noreply.github.com>
Date: Sun, 6 Sep 2026 04:01:27 -0400
Subject: [PATCH 1/2] fix(web): Claude prompt suggestion is bare text instead
of a boxed chip
The suggestion above the composer rendered as a bordered, filled, shadowed
chip, which read as a second card stacked on the composer. It is now plain
muted text with the sparkle icon that brightens on hover. Position, width
cap, click behavior, and the overflow tooltip are unchanged.
---
apps/web/src/components/chat/ChatComposer.tsx | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/apps/web/src/components/chat/ChatComposer.tsx b/apps/web/src/components/chat/ChatComposer.tsx
index 36adda4d..afbb2e72 100644
--- a/apps/web/src/components/chat/ChatComposer.tsx
+++ b/apps/web/src/components/chat/ChatComposer.tsx
@@ -3033,21 +3033,23 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
>
{/* Float the suggestion above the composer (like the scroll-to-bottom button) so it
overlays the bottom of the message list instead of consuming input-bar height.
- Width is capped below half the composer so it never reaches the centered
- scroll-to-bottom button that shares this band. */}
+ It is bare text rather than a chip: no border, fill, or shadow, so it reads as
+ a quiet hint instead of a second card stacked on the composer. Width is capped
+ below half the composer so it never reaches the centered scroll-to-bottom
+ button that shares this band. */}
{latestPromptSuggestion && latestPromptSuggestionDisplayText && !isComposerCollapsedMobile ? (
-
+
applyPromptSuggestion(latestPromptSuggestion)}
>
-
+
Date: Sun, 6 Sep 2026 04:10:12 -0400
Subject: [PATCH 2/2] feat(web): Tab accepts the Claude prompt suggestion
With the composer focused and empty, pressing Tab drops the floating Claude
suggestion into the composer, the same as clicking it. The suggestion shows
a Tab hint on hover and keyboard focus. Shift+Tab still toggles plan mode,
and Tab still picks the highlighted item while a slash or mention menu is
open.
---
apps/web/src/components/ChatView.browser.tsx | 29 +++++++++++++++++++
apps/web/src/components/chat/ChatComposer.tsx | 17 +++++++++++
2 files changed, 46 insertions(+)
diff --git a/apps/web/src/components/ChatView.browser.tsx b/apps/web/src/components/ChatView.browser.tsx
index 9efba9ab..50b49e6b 100644
--- a/apps/web/src/components/ChatView.browser.tsx
+++ b/apps/web/src/components/ChatView.browser.tsx
@@ -10082,6 +10082,35 @@ describe("ChatView timeline estimator parity (full app)", () => {
}
});
+ it("accepts the prompt suggestion with Tab from the focused composer", async () => {
+ const suggestion = "Commit this and open the PR";
+ const { mounted } = await mountPromptSuggestionChip(suggestion);
+ try {
+ const composerEditor = await waitForComposerEditor();
+ composerEditor.focus();
+ composerEditor.dispatchEvent(
+ new KeyboardEvent("keydown", { key: "Tab", bubbles: true, cancelable: true }),
+ );
+
+ await waitForElement(
+ () => (composerEditor.textContent?.trim() === suggestion ? composerEditor : null),
+ () =>
+ `Tab never moved the suggestion into the composer; it holds "${
+ composerEditor.textContent ?? ""
+ }".`,
+ );
+ // Accepting the suggestion consumes it, so the chip goes away.
+ await waitForElement(
+ () => (document.querySelector('[data-prompt-suggestion="true"]') ? null : document.body),
+ "The prompt suggestion chip stayed visible after Tab accepted it.",
+ );
+ // Focus stays in the composer instead of tabbing out to the toolbar.
+ expect(document.activeElement).toBe(composerEditor);
+ } finally {
+ await mounted.cleanup();
+ }
+ });
+
it("keeps the slash-command menu visible above the composer", async () => {
const mounted = await mountChatView({
viewport: DEFAULT_VIEWPORT,
diff --git a/apps/web/src/components/chat/ChatComposer.tsx b/apps/web/src/components/chat/ChatComposer.tsx
index afbb2e72..f44dee17 100644
--- a/apps/web/src/components/chat/ChatComposer.tsx
+++ b/apps/web/src/components/chat/ChatComposer.tsx
@@ -145,6 +145,7 @@ import {
useProviderRateLimitResetCredit,
} from "../ProviderRateLimitResetCredit";
import { CircleAlertIcon, FileTextIcon, SparklesIcon, XIcon } from "lucide-react";
+import { Kbd } from "../ui/kbd";
import { proposedPlanTitle } from "../../proposedPlan";
import {
getProviderDisplayName,
@@ -2590,6 +2591,14 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
return true;
}
}
+ // Tab accepts the Claude suggestion floating above the composer. The
+ // suggestion only exists while the composer is empty, so this never
+ // clobbers typed text, and the menu branch above already claimed Tab when
+ // a slash or mention menu is open.
+ if (key === "Tab" && latestPromptSuggestion) {
+ applyPromptSuggestion(latestPromptSuggestion);
+ return true;
+ }
if (key === "Enter" && !event.shiftKey) {
submitComposer();
return true;
@@ -3057,6 +3066,14 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
>
{latestPromptSuggestionDisplayText}
+ {/* Tab hint stays hidden until hover or keyboard focus so the
+ resting state is just the sparkle and the words. */}
+
+ Tab
+
}
/>