🎨 Palette: Add Cmd+K keyboard shortcut to search - #154
Conversation
This commit implements a global keyboard shortcut (Cmd+K on Mac, Ctrl+K on Windows/Linux) to quickly focus the main search input field. It also displays a dynamic, OS-specific hint (`⌘K` or `Ctrl K`) within the search input when empty, improving discoverability. Changes: - Added `keydown` event listener in `src/app/page.tsx` - Used `isMounted` state pattern to prevent SSR hydration mismatches for the OS-specific hint and `aria-keyshortcuts` - Added dynamic `aria-keyshortcuts` attribute to the search input - Styled the shortcut hint with `pointer-events-none` so it doesn't block clicks to the input - Updated the "Clear search" button to return focus to the input after clearing - Added learning regarding `aria-keyshortcuts`, `isMounted` and `pointer-events-none` to `.Jules/palette.md` Co-authored-by: corebrimtech <175357468+corebrimtech@users.noreply.github.com>
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📝 WalkthroughWalkthroughA journal entry documents requirements for keyboard shortcut implementation, while the search UI adds global Ctrl+K/Cmd+K shortcut support with OS-specific display hints, dynamic Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.Jules/palette.md:
- Around line 27-29: The journal entry header "## 2026-10-27 - Keyboard
Shortcuts for Search" is dated in the future; update that header to today's date
(e.g., "## 2026-03-24 - Keyboard Shortcuts for Search") so the timeline stays
accurate, locating the entry by the exact header text "Keyboard Shortcuts for
Search" and replacing only the date portion while keeping the rest of the
paragraph unchanged.
In `@src/app/page.tsx`:
- Line 365: The Input component does not forward refs so searchInputRef passed
from page.tsx never reaches the underlying <input>, breaking focus for the
Cmd/Ctrl+K handler and after clearing search; fix by converting the Input
component in src/components/ui/input.tsx to use React.forwardRef, accept a ref
parameter typed as HTMLInputElement (e.g., forwardRef<HTMLInputElement,
InputProps>), pass that ref to the actual <input> element inside the component,
and adjust the InputProps to extend React.InputHTMLAttributes<HTMLInputElement>
(or ComponentPropsWithoutRef<'input'>) so all native input props continue to
work. Ensure the exported Input remains the same name so existing usages (e.g.,
the ref={searchInputRef} in page.tsx) pick up the forwarded ref.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 26c66790-f113-48ca-8541-9bc6fa8f8d3a
⛔ Files ignored due to path filters (3)
prisma/dev.dbis excluded by!**/*.dbverification_cleared.pngis excluded by!**/*.pngverification_with_text.pngis excluded by!**/*.png
📒 Files selected for processing (2)
.Jules/palette.mdsrc/app/page.tsx
| ## 2026-10-27 - Keyboard Shortcuts for Search | ||
| **Learning:** Interactive elements with keyboard shortcuts must dynamically set the `aria-keyshortcuts` attribute based on the OS modifier (e.g., `Meta+K` vs `Control+K` using `navigator.platform`) instead of being hardcoded, to correctly announce the shortcut to assistive technology. Moreover, conditionally rendering OS-specific hints requires delaying rendering using an `isMounted` state pattern to avoid SSR hydration mismatches, and visual overlays should use `pointer-events-none` to allow clicking through the hint to focus the underlying input. | ||
| **Action:** Always dynamically detect OS with an `isMounted` guard for shortcut keys, use `aria-keyshortcuts`, and add `pointer-events-none` to any overlay hints inside input wrappers. |
There was a problem hiding this comment.
Future-dated journal entry can confuse change chronology.
The new section is dated 2026-10-27, which is in the future (current date is March 24, 2026). Please use the actual entry date to keep the journal timeline reliable.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.Jules/palette.md around lines 27 - 29, The journal entry header "##
2026-10-27 - Keyboard Shortcuts for Search" is dated in the future; update that
header to today's date (e.g., "## 2026-03-24 - Keyboard Shortcuts for Search")
so the timeline stays accurate, locating the entry by the exact header text
"Keyboard Shortcuts for Search" and replacing only the date portion while
keeping the rest of the paragraph unchanged.
| <div className="relative group"> | ||
| <Search className="absolute left-4 top-1/2 transform -translate-y-1/2 h-5 w-5 text-slate-400 group-focus-within:text-primary transition-colors pointer-events-none" /> | ||
| <Input | ||
| ref={searchInputRef} |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify whether Input forwards refs and where ref is consumed.
set -euo pipefail
echo "== Input component definition (expect forwardRef for proper ref wiring) =="
fd 'input\.tsx$' | xargs -I{} rg -n -C3 'forwardRef|function Input|const Input' {}
echo
echo "== Input usages with ref prop (expect these to rely on forwarded ref) =="
rg -nP --type=tsx -C2 '<Input[^>]*\bref='Repository: mkk2026/Security.News.Scraper
Length of output: 434
🏁 Script executed:
#!/bin/bash
# Verify Input component and ref usage more carefully
set -euo pipefail
echo "=== Current Input component (full file) ==="
find . -path "*/components/ui/input.tsx" -type f | head -1 | xargs cat
echo
echo "=== Ref usage in page.tsx around line 365 ==="
sed -n '360,370p' src/app/page.tsx
echo
echo "=== searchInputRef definition in page.tsx ==="
rg -n 'searchInputRef' src/app/page.tsx | head -20
echo
echo "=== Line 113 context in page.tsx ==="
sed -n '108,118p' src/app/page.tsx
echo
echo "=== Line 384 context in page.tsx ==="
sed -n '379,389p' src/app/page.tsxRepository: mkk2026/Security.News.Scraper
Length of output: 3300
ref won't work because Input does not forward refs.
The Input component in src/components/ui/input.tsx is defined as a plain function component without React.forwardRef. When ref={searchInputRef} is passed at line 365, the ref never connects to the underlying <input> element, leaving searchInputRef.current as null. This breaks focus on Cmd/Ctrl+K (line 113) and after clearing search (line 384).
🔧 Proposed fix (in src/components/ui/input.tsx)
import * as React from "react"
import { cn } from "@/lib/utils"
-function Input({ className, type, ...props }: React.ComponentProps<"input">) {
- return (
- <input
- type={type}
- data-slot="input"
- className={cn(
- "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
- "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
- "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
- className
- )}
- {...props}
- />
- )
-}
+const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
+ ({ className, type, ...props }, ref) => {
+ return (
+ <input
+ ref={ref}
+ type={type}
+ data-slot="input"
+ className={cn(
+ "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
+ "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
+ "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
+ className
+ )}
+ {...props}
+ />
+ )
+ }
+)
+Input.displayName = "Input"
export { Input }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/app/page.tsx` at line 365, The Input component does not forward refs so
searchInputRef passed from page.tsx never reaches the underlying <input>,
breaking focus for the Cmd/Ctrl+K handler and after clearing search; fix by
converting the Input component in src/components/ui/input.tsx to use
React.forwardRef, accept a ref parameter typed as HTMLInputElement (e.g.,
forwardRef<HTMLInputElement, InputProps>), pass that ref to the actual <input>
element inside the component, and adjust the InputProps to extend
React.InputHTMLAttributes<HTMLInputElement> (or
ComponentPropsWithoutRef<'input'>) so all native input props continue to work.
Ensure the exported Input remains the same name so existing usages (e.g., the
ref={searchInputRef} in page.tsx) pick up the forwarded ref.
💡 What: Added a global keyboard shortcut (Cmd+K / Ctrl+K) to quickly focus the main search bar, complete with a visual hint inside the input field.
🎯 Why: Power users expect a quick way to search without reaching for the mouse. Adding a keyboard shortcut significantly speeds up navigation and filtering, improving the overall workflow.
📸 Before/After:
Before: The search input was only focusable via mouse click or manual tabbing.
After: The search input can be focused instantly with Cmd+K (Mac) or Ctrl+K (Windows/Linux). A visual hint (e.g.,
⌘K) is displayed when the input is empty to teach users the shortcut.♿ Accessibility:
aria-keyshortcutsto theInputelement so screen readers can announce the available shortcut.pointer-events-noneso it doesn't interfere with clicking the input field beneath it.PR created automatically by Jules for task 6607717908807149004 started by @corebrimtech
Summary by CodeRabbit