Skip to content

🔼 refactor: Improve UX for Command Popovers - #12677

Merged
danny-avila merged 4 commits into
devfrom
refactor/mention-prompts-popover-ux
Apr 15, 2026
Merged

danny-avila merged 4 commits into
devfrom
refactor/mention-prompts-popover-ux

Conversation

@danny-avila

@danny-avila danny-avila commented Apr 15, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Fixes several UX issues with the @, +, and / command popovers in the chat input:

  1. @/+ command text not clearing from textarea — When the mention popover opened, the command character stayed visible in the textarea (unlike / which cleared correctly). Root cause: ChatForm subscribed to the mention popover atoms via useRecoilState, causing it to re-render when the popover opened, which interfered with the textarea clearing logic. The / command avoided this because PromptsCommand managed its popover state internally.

  2. Perpetual loading spinner for mentions — useMentions included isLoadingAgents unconditionally in its aggregate isLoading flag, but the agents query is often disabled (no agent access / model select off). With React Query v4, disabled queries without cache stay in loading status, causing a permanent spinner.

  3. Overly broad command trigger fallback — The fast-typing fallback in shouldTriggerCommand would re-trigger the popover on navigation keys (ArrowLeft, Delete) within short command text, since it only checked text length without verifying cursor position.

Changes

Architecture: Align Mention with PromptsCommand pattern

  • Mention.tsx — Wrapped in a MentionPopoverContainer (memoized) that reads its popover atom internally via useRecoilValue and conditionally renders the content. Uses useSetRecoilState (write-only) to close itself. Replaces the old setShowMentionPopover prop with popoverAtom.
  • ChatForm.tsx — Removed useRecoilState subscriptions for showMentionPopoverFamily and showPlusPopoverFamily. ChatForm no longer re-renders when these popover states change. Both <Mention> components are rendered unconditionally — they manage their own visibility internally.
  • useHandleKeyUp.ts — All three popover setters (@, +, /) now use useSetRecoilState internally. Removed setter props from the hook parameters, fully decoupling it from ChatForm. Moved the isAssistantsEndpoint guard (previously in ChatForm's render) into the + command handler.

Bug fixes

  • useMentions.ts — Exposed aggregate isLoading from all data queries. Gated isLoadingAgents behind agentQueryEnabled so a disabled query can't cause perpetual loading.
  • useHandleKeyUp.ts — shouldTriggerCommand fallback now requires startPos === text.length (cursor at end) in addition to the length cap, preventing spurious triggers during text navigation.

UX improvements

  • Mention.tsx / PromptsCommand.tsx — Replaced autoFocus with a callback ref (initInputRef) that focuses the input, transfers command text as a search prefix, and clears the textarea in one synchronous pass. Shows a loading spinner when data is still fetching and no matches exist yet.

Test plan

  • useHandleKeyUp unit tests (37 tests) — covers command triggering, fast typing, navigation keys, paste protection, toggles, permission gating, and endpoint gating
  • Manual: type @ → popover opens, textarea clears, command char is gone
  • Manual: type + → same behavior (not on assistants endpoints)
  • Manual: type / → same behavior (unchanged)
  • Manual: verify loading spinner appears briefly when mention data is fetching
  • Manual: user without agent access sees no perpetual spinner

* Added loading state handling in Mention and PromptsCommand components to display a spinner when data is being fetched.
* Refactored onFocus logic to clear the textarea and set the search value based on command character input.
* Introduced a new `isLoading` state in the useMentions hook to manage loading indicators across multiple data queries.
* Added unit tests for the useHandleKeyUp hook to ensure command triggering works correctly under various conditions.
Copilot AI review requested due to automatic review settings April 15, 2026 18:31
@danny-avila

Copy link
Copy Markdown
Collaborator Author

@codex review

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors command popover UX to better handle fast typing and loading states, while adding test coverage for command triggering behavior.

Changes:

  • Added aggregated isLoading state to useMentions to drive consistent loading indicators.
  • Updated command-trigger detection logic in useHandleKeyUp to support fast typists via a short-length fallback.
  • Added Jest unit tests for useHandleKeyUp and updated popover components to show spinners and improve focus behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
client/src/hooks/Input/useMentions.ts Exposes an aggregated isLoading flag across multiple mention-related queries.
client/src/hooks/Input/useHandleKeyUp.ts Adjusts command trigger heuristics (adds short-length fallback).
client/src/hooks/Input/useHandleKeyUp.spec.ts Adds unit tests covering command triggering, toggles, and permission gating.
client/src/components/Chat/Input/PromptsCommand.tsx Improves focus behavior and renders a loading spinner when opening with no matches during load.
client/src/components/Chat/Input/Mention.tsx Adds loading spinner rendering and refines focus behavior; wires in useMentions().isLoading.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 32 to 38
const startPos = textAreaRef.current?.selectionStart;
if (typeof startPos !== 'number') {
return false;
}

return startPos === 1;
return startPos === 1 || text.length <= MAX_COMMAND_TRIGGER_LENGTH;
};

Copilot AI Apr 15, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldTriggerCommand now returns true whenever the textarea starts with the command char and the text is short, regardless of which key was pressed or where the cursor is. This means non-text/navigation keys (e.g. ArrowLeft/ArrowRight/Home/End) can inadvertently open a command popover as long as the message begins with '/', '@', or '+' and is <= 5 chars. Consider additionally gating on the key event (e.g., only trigger on printable character keys) and/or requiring selectionStart to be at the end of the text for the length-based fallback; also add a unit test that verifies arrow/navigation keys do not trigger popovers.

Copilot uses AI. Check for mistakes.
Comment on lines +201 to +205
onFocus={() => {
setOpen(true);
const textarea = textAreaRef.current;
if (!textarea) {
return;

Copilot AI Apr 15, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new onFocus handler contains fairly involved logic (reading/clearing the textarea, extracting the command search text, dispatching an input event) that is now duplicated in multiple popover components (e.g., here and in PromptsCommand). Consider extracting this into a shared helper (or small hook) so future tweaks to the command-focus behavior don’t drift between components.

Copilot uses AI. Check for mistakes.
Comment on lines +226 to +230
onFocus={() => {
setOpen(true);
const textarea = textAreaRef.current;
if (!textarea) {
return;

Copilot AI Apr 15, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The textarea-syncing logic inside this onFocus handler is duplicated with the similar block in Mention. Consider extracting a shared helper/hook for the command-popover focus behavior to reduce duplication and ensure fixes (e.g. search extraction / textarea clearing) stay consistent across popovers.

Copilot uses AI. Check for mistakes.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ee3c10585b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/hooks/Input/useHandleKeyUp.ts Outdated
Comment thread client/src/hooks/Input/useMentions.ts Outdated
* Added tests to ensure that the command popovers do not trigger when the cursor is mid-text after pressing ArrowLeft or Delete.
* Updated the shouldTriggerCommand function to refine the conditions under which commands are triggered based on cursor position.
* Improved agent query handling in useMentions hook for better performance and clarity.
* Refactored Mention and PromptsCommand components to utilize Recoil state for popover visibility, improving state management and reducing prop drilling.
* Simplified onFocus logic to enhance user experience when interacting with command inputs.
* Added unit tests for useHandleKeyUp to ensure proper command handling and popover visibility based on user input.
* Improved performance by memoizing popover state and reducing unnecessary re-renders.
@LibreChat-AI LibreChat-AI deleted a comment from github-actions Bot Apr 15, 2026
@LibreChat-AI LibreChat-AI deleted a comment from github-actions Bot Apr 15, 2026
@danny-avila

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a4d9b4bf87

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/components/Chat/Input/PromptsCommand.tsx Outdated
Comment thread client/src/components/Chat/Input/Mention.tsx Outdated
@LibreChat-AI LibreChat-AI deleted a comment from github-actions Bot Apr 15, 2026
@danny-avila

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d338571a01

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/components/Chat/Input/ChatForm.tsx
@danny-avila
danny-avila force-pushed the refactor/mention-prompts-popover-ux branch from d338571 to ddc08f1 Compare April 15, 2026 20:54
@github-actions

Copy link
Copy Markdown
Contributor

GitNexus: ❌ deploy failed

The deploy failed — the previous index (if any) continues to be served.
Deploy run

- Fix endpointType regression: add effectiveEndpointByIndex selector
  that returns endpointType ?? endpoint, matching the original ChatForm
  guard for custom endpoints proxying assistants
- Extract duplicated initInputRef callback into shared useInitPopoverInput
  hook, used by both Mention and PromptsCommand
- Add navigation keys (ArrowLeft, ArrowRight, ArrowDown, Home, End,
  Delete) to invalidKeys to prevent false popover triggers
- Add endpoint gating tests for assistants/azureAssistants blocking the
  + command
- Remove unused _index param from MentionContent
@danny-avila
danny-avila force-pushed the refactor/mention-prompts-popover-ux branch from ddc08f1 to 7a2c136 Compare April 15, 2026 21:36
@github-actions

Copy link
Copy Markdown
Contributor

GitNexus: ❌ deploy failed

The deploy failed — the previous index (if any) continues to be served.
Deploy run

@danny-avila
danny-avila merged commit 49f228d into dev Apr 15, 2026
8 checks passed
@danny-avila
danny-avila deleted the refactor/mention-prompts-popover-ux branch April 15, 2026 21:47
krgokul pushed a commit to syedhabib39/LibreChat that referenced this pull request Apr 20, 2026
* refactor: Improve UX for Command Popovers

* Added loading state handling in Mention and PromptsCommand components to display a spinner when data is being fetched.
* Refactored onFocus logic to clear the textarea and set the search value based on command character input.
* Introduced a new `isLoading` state in the useMentions hook to manage loading indicators across multiple data queries.
* Added unit tests for the useHandleKeyUp hook to ensure command triggering works correctly under various conditions.

* ci: useHandleKeyUp tests for command navigation

* Added tests to ensure that the command popovers do not trigger when the cursor is mid-text after pressing ArrowLeft or Delete.
* Updated the shouldTriggerCommand function to refine the conditions under which commands are triggered based on cursor position.
* Improved agent query handling in useMentions hook for better performance and clarity.

* refactor: Optimize Mention and PromptsCommand Components

* Refactored Mention and PromptsCommand components to utilize Recoil state for popover visibility, improving state management and reducing prop drilling.
* Simplified onFocus logic to enhance user experience when interacting with command inputs.
* Added unit tests for useHandleKeyUp to ensure proper command handling and popover visibility based on user input.
* Improved performance by memoizing popover state and reducing unnecessary re-renders.

* fix: Address review findings for command popover refactor

- Fix endpointType regression: add effectiveEndpointByIndex selector
  that returns endpointType ?? endpoint, matching the original ChatForm
  guard for custom endpoints proxying assistants
- Extract duplicated initInputRef callback into shared useInitPopoverInput
  hook, used by both Mention and PromptsCommand
- Add navigation keys (ArrowLeft, ArrowRight, ArrowDown, Home, End,
  Delete) to invalidKeys to prevent false popover triggers
- Add endpoint gating tests for assistants/azureAssistants blocking the
  + command
- Remove unused _index param from MentionContent
krgokul pushed a commit to syedhabib39/LibreChat that referenced this pull request Apr 21, 2026
* refactor: Improve UX for Command Popovers

* Added loading state handling in Mention and PromptsCommand components to display a spinner when data is being fetched.
* Refactored onFocus logic to clear the textarea and set the search value based on command character input.
* Introduced a new `isLoading` state in the useMentions hook to manage loading indicators across multiple data queries.
* Added unit tests for the useHandleKeyUp hook to ensure command triggering works correctly under various conditions.

* ci: useHandleKeyUp tests for command navigation

* Added tests to ensure that the command popovers do not trigger when the cursor is mid-text after pressing ArrowLeft or Delete.
* Updated the shouldTriggerCommand function to refine the conditions under which commands are triggered based on cursor position.
* Improved agent query handling in useMentions hook for better performance and clarity.

* refactor: Optimize Mention and PromptsCommand Components

* Refactored Mention and PromptsCommand components to utilize Recoil state for popover visibility, improving state management and reducing prop drilling.
* Simplified onFocus logic to enhance user experience when interacting with command inputs.
* Added unit tests for useHandleKeyUp to ensure proper command handling and popover visibility based on user input.
* Improved performance by memoizing popover state and reducing unnecessary re-renders.

* fix: Address review findings for command popover refactor

- Fix endpointType regression: add effectiveEndpointByIndex selector
  that returns endpointType ?? endpoint, matching the original ChatForm
  guard for custom endpoints proxying assistants
- Extract duplicated initInputRef callback into shared useInitPopoverInput
  hook, used by both Mention and PromptsCommand
- Add navigation keys (ArrowLeft, ArrowRight, ArrowDown, Home, End,
  Delete) to invalidKeys to prevent false popover triggers
- Add endpoint gating tests for assistants/azureAssistants blocking the
  + command
- Remove unused _index param from MentionContent
umzcio pushed a commit to umzcio/LibreChat that referenced this pull request May 7, 2026
Resolves conflicts from:
- Sidebar Icon Toggle (LibreChat-AI#12642) - kept our branding logo, took upstream's
  setActive prop change on NewChatButton
- Command Popover UX (LibreChat-AI#12677) - adopted upstream's popoverAtom pattern in
  ChatForm/Mention, kept Jotai in useHandleKeyUp
- Preserve Selected Artifact (LibreChat-AI#12601) - accepted upstream's fix
- Entra ID Group Sync (LibreChat-AI#12606) - accepted upstream's expanded logic
- families.ts - kept our Jotai atomFamily definitions, added
  effectiveEndpointByIndex as Jotai selector

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
jcbartle pushed a commit to jcbartle/LibreChat that referenced this pull request May 11, 2026
* refactor: Improve UX for Command Popovers

* Added loading state handling in Mention and PromptsCommand components to display a spinner when data is being fetched.
* Refactored onFocus logic to clear the textarea and set the search value based on command character input.
* Introduced a new `isLoading` state in the useMentions hook to manage loading indicators across multiple data queries.
* Added unit tests for the useHandleKeyUp hook to ensure command triggering works correctly under various conditions.

* ci: useHandleKeyUp tests for command navigation

* Added tests to ensure that the command popovers do not trigger when the cursor is mid-text after pressing ArrowLeft or Delete.
* Updated the shouldTriggerCommand function to refine the conditions under which commands are triggered based on cursor position.
* Improved agent query handling in useMentions hook for better performance and clarity.

* refactor: Optimize Mention and PromptsCommand Components

* Refactored Mention and PromptsCommand components to utilize Recoil state for popover visibility, improving state management and reducing prop drilling.
* Simplified onFocus logic to enhance user experience when interacting with command inputs.
* Added unit tests for useHandleKeyUp to ensure proper command handling and popover visibility based on user input.
* Improved performance by memoizing popover state and reducing unnecessary re-renders.

* fix: Address review findings for command popover refactor

- Fix endpointType regression: add effectiveEndpointByIndex selector
  that returns endpointType ?? endpoint, matching the original ChatForm
  guard for custom endpoints proxying assistants
- Extract duplicated initInputRef callback into shared useInitPopoverInput
  hook, used by both Mention and PromptsCommand
- Add navigation keys (ArrowLeft, ArrowRight, ArrowDown, Home, End,
  Delete) to invalidKeys to prevent false popover triggers
- Add endpoint gating tests for assistants/azureAssistants blocking the
  + command
- Remove unused _index param from MentionContent
ThomasVuNguyen pushed a commit to ThomasVuNguyen/LibreChat that referenced this pull request Jul 15, 2026
* refactor: Improve UX for Command Popovers

* Added loading state handling in Mention and PromptsCommand components to display a spinner when data is being fetched.
* Refactored onFocus logic to clear the textarea and set the search value based on command character input.
* Introduced a new `isLoading` state in the useMentions hook to manage loading indicators across multiple data queries.
* Added unit tests for the useHandleKeyUp hook to ensure command triggering works correctly under various conditions.

* ci: useHandleKeyUp tests for command navigation

* Added tests to ensure that the command popovers do not trigger when the cursor is mid-text after pressing ArrowLeft or Delete.
* Updated the shouldTriggerCommand function to refine the conditions under which commands are triggered based on cursor position.
* Improved agent query handling in useMentions hook for better performance and clarity.

* refactor: Optimize Mention and PromptsCommand Components

* Refactored Mention and PromptsCommand components to utilize Recoil state for popover visibility, improving state management and reducing prop drilling.
* Simplified onFocus logic to enhance user experience when interacting with command inputs.
* Added unit tests for useHandleKeyUp to ensure proper command handling and popover visibility based on user input.
* Improved performance by memoizing popover state and reducing unnecessary re-renders.

* fix: Address review findings for command popover refactor

- Fix endpointType regression: add effectiveEndpointByIndex selector
  that returns endpointType ?? endpoint, matching the original ChatForm
  guard for custom endpoints proxying assistants
- Extract duplicated initInputRef callback into shared useInitPopoverInput
  hook, used by both Mention and PromptsCommand
- Add navigation keys (ArrowLeft, ArrowRight, ArrowDown, Home, End,
  Delete) to invalidKeys to prevent false popover triggers
- Add endpoint gating tests for assistants/azureAssistants blocking the
  + command
- Remove unused _index param from MentionContent
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.

2 participants