Skip to content

Conversation

@codegen-sh
Copy link
Contributor

@codegen-sh codegen-sh bot commented Nov 11, 2025

Overview

This PR adds the ability to open select dropdowns and start searching immediately when typing while focused on the select trigger. This improves the user experience by making select components feel more responsive and keyboard-friendly.

Changes

  • Type-to-open functionality: When focused on a select trigger, typing any printable character will:
    • Open the dropdown if it's not already open
    • Focus the search input
    • Pre-populate the search with the typed character
  • Auto-focus search input: When the popover opens (via any method), the search input is automatically focused if searchable is enabled
  • Clear search on close: The search query is automatically cleared when the popover closes
  • Preserved keyboard navigation: All standard keyboard shortcuts remain functional (Enter, Space, Arrow keys, Escape, Tab)

Testing

The changes were tested and the component builds successfully:

  • yarn lint passes
  • yarn workspace @lambdacurry/forms build succeeds

Example Usage

<USStateSelect name="state" label="US State" />

Now when you focus the select and start typing "Cal", the dropdown will open and show California in the filtered results.

Implementation Details

  • Added searchInputRef to track the search input element
  • Added handleTriggerKeyDown to detect printable characters and trigger the open/search behavior
  • Modified the useEffect to auto-focus the search input when opening
  • Search query is cleared when the popover closes to reset state

Requested by: Jake Ruesink (@jake)


💻 View my workAbout Codegen
⛔ Remove Codegen from PR🚫 Ban action checks

Summary by CodeRabbit

  • New Features
    • Added keyboard search to the Select component—typing immediately searches when the dropdown opens.
    • Improved search input focus behavior, automatically focusing the search field on open.
    • Enhanced selected item visibility by auto-scrolling it into view when the dropdown opens.

- Add keydown handler to select trigger that opens popover when typing printable characters
- Automatically focus search input when popover opens
- Set initial search query to the typed character
- Clear search query when popover closes
- Maintains normal keyboard navigation (Enter, Space, Arrow keys, etc.)
@bolt-new-by-stackblitz
Copy link

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@coderabbitai
Copy link

coderabbitai bot commented Nov 11, 2025

Walkthrough

The Select component now features enhanced keyboard interaction and search input management. Changes include adding a search input ref, focusing the search field when the popover opens, opening the popover via keyboard input with instant search query population, clearing the search query on close, and ensuring the selected item remains in view.

Changes

Cohort / File(s) Change Summary
Select Component Search & Keyboard Interaction
packages/components/src/ui/select.tsx
Added searchInputRef for ref management; implemented handleTriggerKeyDown to open popover and pre-fill search query on printable character input; attached keyboard handler to trigger; focus search input on popover open (when searchable) and clear search query on close; scroll selected item into view; adjusted effect dependencies to include searchable flag.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Trigger
    participant Component
    participant SearchInput
    participant Popover

    User->>Trigger: Type printable character
    Trigger->>Component: onKeyDown event
    Component->>Component: handleTriggerKeyDown
    Note over Component: Pre-fill searchQuery with character
    Component->>Popover: Open popover
    Popover->>Component: onOpenChange triggered
    Component->>SearchInput: Focus via searchInputRef
    Component->>Component: Scroll selected item into view
    
    User->>Popover: Close/Blur
    Popover->>Component: onOpenChange triggered
    Component->>Component: Clear searchQuery
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Focus areas requiring extra attention:
    • handleTriggerKeyDown logic: verify keyboard event filtering for printable characters and proper event forwarding
    • Ref management: ensure searchInputRef is properly initialized, passed, and focused without race conditions
    • Effect dependency chain: confirm searchable inclusion doesn't cause unintended re-runs or side effects
    • Popover open/close state management: verify searchQuery clearing doesn't interfere with other close handlers

Possibly related PRs

Poem

🐰 A select so keen, it hears your keys,
Search pops open with such ease,
Focus swift on input field,
Keyboard magic now revealed! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: enabling typing to open and search select dropdowns, which aligns with the core functionality added in the changeset.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codegen-bot/type-to-open-select-f85f09

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7788aa7 and 39156a7.

📒 Files selected for processing (1)
  • packages/components/src/ui/select.tsx (4 hunks)
🧰 Additional context used
📓 Path-based instructions (14)
packages/components/src/ui/**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/form-component-patterns.mdc)

packages/components/src/ui/**/*.tsx: Build on @radix-ui components as the foundation for base UI components
Follow the component composition pattern for UI components that accept form integration

Files:

  • packages/components/src/ui/select.tsx
packages/components/src/ui/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/form-component-patterns.mdc)

Base UI components should be named as ComponentName in ui/ directory

Files:

  • packages/components/src/ui/select.tsx
**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/form-component-patterns.mdc)

**/*.{tsx,ts}: Props interfaces should be named as ComponentNameProps
Form schemas should be named formSchema or componentNameSchema

Files:

  • packages/components/src/ui/select.tsx
packages/components/src/{remix-hook-form,ui}/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/form-component-patterns.mdc)

Always export both the component and its props type

Files:

  • packages/components/src/ui/select.tsx
{apps,packages}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo-organization.mdc)

{apps,packages}/**/*.{ts,tsx}: Use package name imports for published packages (e.g., import { TextField } from '@lambdacurry/forms/remix-hook-form')
Import from specific entry points (e.g., import { TextField } from '@lambdacurry/forms/remix-hook-form/text-field')
Do not use relative imports across packages (e.g., avoid import { TextField } from '../../packages/components/src/remix-hook-form/text-field')
Order imports: 1) external libraries, 2) internal package imports, 3) cross-package imports, 4) type-only imports (grouped separately)

Files:

  • packages/components/src/ui/select.tsx
{apps,packages}/**/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo-organization.mdc)

{apps,packages}/**/src/**/*.{ts,tsx}: Use relative imports within the same package (e.g., import { FormControl } from './form')
Use relative imports for sibling directories (e.g., import { Button } from '../ui/button')

Files:

  • packages/components/src/ui/select.tsx
packages/components/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo-organization.mdc)

packages/components/src/**/*.{ts,tsx}: Always export both component and props type (e.g., export { ComponentName }; export type { ComponentNameProps };)
Use named exports for components for better tree-shaking (e.g., export const ComponentName = ...; avoid default exports)
Avoid default exports for components
Use tree-shaking friendly exports

Files:

  • packages/components/src/ui/select.tsx
{apps,packages}/**/src/**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/monorepo-organization.mdc)

{apps,packages}/**/src/**/*.{tsx,ts}: Use kebab-case for component file names (e.g., text-field.tsx, data-table.tsx)
Match component name in PascalCase to the exported component from the file (e.g., text-field.tsx exports TextField)

Files:

  • packages/components/src/ui/select.tsx
packages/components/src/ui/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo-organization.mdc)

Don't import from remix-hook-form package in ui components

Files:

  • packages/components/src/ui/select.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo-organization.mdc)

Avoid circular dependencies

**/*.{ts,tsx}: Indent with 2 spaces, max line width 120, and use single quotes (Biome-enforced)
Use PascalCase for component and type names
Name hooks in camelCase with a use* prefix
Organize imports automatically with Biome
Use named exports only

Files:

  • packages/components/src/ui/select.tsx
packages/components/src/**

📄 CodeRabbit inference engine (AGENTS.md)

Place all @lambdacurry/forms source under packages/components/src and treat it as the only editable source for the package

Files:

  • packages/components/src/ui/select.tsx
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

**/*.tsx: Keep React components pure and fully typed
Define explicit props interfaces for React components
Use React 19 ref patterns (forwardRef, useImperativeHandle as appropriate)

Files:

  • packages/components/src/ui/select.tsx
**/*.{ts,tsx,mdx}

📄 CodeRabbit inference engine (AGENTS.md)

Use kebab-case for filenames (e.g., text-field.tsx, data-table-filter/**)

Files:

  • packages/components/src/ui/select.tsx
packages/**/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Avoid cross-package relative imports in the monorepo

Files:

  • packages/components/src/ui/select.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (3)
packages/components/src/ui/select.tsx (3)

87-87: LGTM! Ref integration points are correct.

The searchInputRef declaration, onKeyDown handler attachment, and ref passing to SearchInput are all properly implemented. These will work correctly once the ref forwarding issue in DefaultSearchInput (lines 59-62) is resolved.

Also applies to: 171-171, 200-200


93-106: LGTM! Focus and cleanup logic is well-structured.

The effect properly clears the search query on close, focuses the search input on open (when searchable), and scrolls the selected item into view. The use of requestAnimationFrame is appropriate for DOM operations, and the dependencies are correct. The null check on searchInputRef.current provides good defensive coding.


128-154: LGTM! Keyboard handling preserves navigation and enables type-to-open.

The implementation correctly preserves standard keyboard navigation (Enter, Space, Arrow keys, Escape, Tab) while adding type-to-open behavior for printable characters. The modifier key checks prevent conflicts with keyboard shortcuts, and the original onKeyDown is properly forwarded.

The e.key.length === 1 check works for most printable characters. While there might be edge cases with certain keyboard layouts or special characters, this approach is reasonable and will work for the vast majority of users.


Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Contributor

📝 Storybook Preview: View Storybook

This preview will be updated automatically when you push new changes to this PR.

Note: The preview will be available after the workflow completes and the PR is approved for deployment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant