Skip to content

💍 fix: Unclip and Recolor the Keyboard Highlight Ring in Select Popovers - #195

Merged
danny-avila merged 2 commits into
mainfrom
pr/redo-select-highlight-ring
Oct 28, 2026
Merged

danny-avila merged 2 commits into
mainfrom
pr/redo-select-highlight-ring

Conversation

@danny-avila

Copy link
Copy Markdown
Contributor

Pull Request Template

⚠️ Before Submitting a PR, Please Review:

  • Please ensure that you have thoroughly read and understood the Contributing Docs before submitting your Pull Request.

⚠️ Documentation Updates Notice:

  • Kindly note that documentation updates are managed in this repository: librechat.ai

Summary

In every click-ui Select popover, the keyboard-highlighted option's ring is missing its right side. In the light theme it is also drawn in click-ui's near-black accent instead of the app's focus color. This PR supersedes #125 by @dustinhealy and redoes it on current main. It reuses #125's root-cause measurement and its fix, a scoped override that insets the ring by 4px, along with its later recolor commit.

Root cause (from #125). click-ui's Select popover content is overflow: hidden with 1px borders and is as wide as the trigger (--radix-popover-trigger-width). Its option list inherits that same width, so the options overhang the popover's clip box by 2px on the right. click-ui's keyboard rule draws a 2px ring at a -2px offset ([data-input-modality='keyboard'] .generic-menu-item[data-highlighted]), in the option's outer 2px, so the whole right side falls in the clipped overhang. On main at 1280px, with Grants > Audit log > Target type open: the popover spans x 674–961, its clip box 675–960, and the highlighted option 675–962, so the ring's right side (960–962) is clipped away.

Color. Options aren't buttons, so the app's global :focus-visible ring never reaches them. click-ui paints the ring with --click-global-color-accent-default, which is rgb(21, 21, 21) in the light theme, while the app's focus rings use --focus-ring-color (rgb(67, 126, 239)). In dark mode the app already maps click-ui's accent to its dark blue (#6f9cf5), the same as the dark focus color, so only the light theme was wrong.

Fix. One rule in src/styles.css, next to the other scoped focus-ring overrides:

[data-input-modality='keyboard'] [data-highlighted] {
  outline-color: var(--focus-ring-color) !important;
  outline-offset: -4px !important;
}
  • data-input-modality is only set on click-ui's menu panels (Select popover, Dropdown, ContextMenu). So the rule only reaches their options, and only while the keyboard drives them. Hovering with the mouse still shows no ring.
  • !important because click-ui's own rule is more specific.
  • Dropdown menus (the sidebar user menu and the configuration row action menus) use the same click-ui rule. Their items fill the panel, so their ring was already whole. They now get the same color and the same 4px inset as the Selects, so every click-ui menu draws one ring.

Not carried over from #125

  • The click-ui 0.9.1 bump and the Vitest config change (.claude/** exclude, inlining click-ui). main has both since ⬆️ chore: Bump click-ui to 0.9.1 #119.
  • --cui-color-outline as the ring color. This uses --focus-ring-color, the token the app's other focus rings read. It resolves to --cui-color-outline, so the color is the same.
  • The Title method and Title timing selects 💍 fix: Unclip the Keyboard Highlight Ring in Select Popovers #125 was checked on. They are native selects on main now. The click-ui Selects left are the audit log's Target type filter, the configuration Jump to list, the "Add field" picker in renderer/InlineField and the Langfuse destination in sections/LangfuseRenderer.

Change Type

  • Bug fix (non-breaking change which fixes an issue)

Testing

e2e/a11y/menus.spec.ts is new. Like the rest of e2e/a11y, it needs a live backend (E2E_LIVE=1, E2E_BASE_URL). It covers the audit log's Target type Select, the configuration Jump to list (at 1024px, where it shows) and the sidebar user menu (a click-ui Dropdown), each in light and dark mode. Each test opens the menu with Enter, presses ArrowDown and waits until the second option is highlighted. It then reads that option's computed outline in Chromium and checks three things: the ring is solid, its color equals the resolved --focus-ring-color, and no side of it lies outside the padding box of any clipping ancestor up to the menu panel. jsdom does no layout, so a unit test can't see this.

Build Tests that fail
main 5 of 6: the light Selects (near-black ring, right side clipped), the dark Selects (right side clipped), the light user menu (near-black ring)
This PR without outline-color 3: the light Selects and the light user menu
This PR without outline-offset 4: all four Select tests (right side clipped)
This PR none

The dark user-menu test also passes on main, where that ring was already whole and blue. It guards that the inset keeps Dropdown rings whole.

Without E2E_LIVE the spec is skipped. Since #185 the mock backend doesn't answer the capabilities request, so the panel stops at "Could not verify permissions" there and even the user-menu test can't run.

Live check with a production build against a LibreChat backend:

Menu Light Dark
Grants > Audit log > Target type (1280px), second option Whole ring, blue. Its right side ends at the clip edge (x 960). Whole ring, blue
The same Select at 390px, first option ("All", checked) highlighted on open Whole ring, clear of the check mark Same
Configuration > System > Jump to (1024px) Whole ring Whole ring
Configuration > Custom endpoints > row action menu, its unavailable Delete item Whole ring, 2px further inside the item than before Same
Sidebar user menu > Sign out Whole ring, now blue instead of near-black Whole ring, the same blue as before
Mouse hover on a Select option and on a user-menu item No ring, as before

The Langfuse destination Select and the "Add field" picker didn't show up on the test stack: its Features tab has no Langfuse section, and no "Add field" picker appeared on any configuration tab or in the custom endpoint editor. Both render the same click-ui Select popover, so the same rule applies to them.

Test Configuration:

  • LibreChat dev, MongoDB replica set.
  • The panel's production build (bun run build + bun server.ts), Chromium via Playwright 1.61.
  • npx tsc --noEmit, npx eslint src/ e2e/ --max-warnings 0, npx prettier --check on the changed files, bun run test:lint-rules, npx vitest run (3338 tests), bun run build, and E2E_LIVE=1 npx playwright test e2e/a11y/menus.spec.ts against the live stack.

Follow-up

  • The width mismatch itself is a click-ui bug worth reporting upstream: the Select's option list takes width: inherit (the trigger width) inside a popover with borders and overflow: hidden. This override keeps the ring whole either way.

Checklist

  • My code adheres to this project's style guidelines
  • I have performed a self-review of my own code
  • I have commented in any complex areas of my code
  • My changes do not introduce new warnings
  • I have written tests demonstrating that my changes are effective or that my feature works
  • Local unit tests pass with my changes

The keyboard-highlighted option in a click-ui Select popover showed its ring
on three sides only. The popover is as wide as the trigger and clips its
content (overflow: hidden) inside 1px borders, but the option list is also as
wide as the trigger, so options overhang the clip box by 2px on the right.
click-ui draws a 2px ring at a -2px offset, in the option's outer 2px, so the
right side fell entirely in the overhang. The ring also used click-ui's
accent, near-black in the light theme, instead of the app's focus color.

A scoped rule in styles.css, next to the other focus-ring overrides, draws
the ring of a keyboard-highlighted option in --focus-ring-color, 4px inside
the option. data-input-modality is only set on click-ui menu panels, so the
rule reaches click-ui Select, Dropdown and ContextMenu options only, and only
while the keyboard drives them. Dropdown menus (the sidebar user menu, the
row action menus) already showed a whole ring; they now draw the same ring
as the Selects.

e2e/a11y/menus.spec.ts (live backend) measures the highlighted option's ring
in two Selects and the user menu, in light and dark mode: solid, in the focus
color, and inside every clipping ancestor up to the menu.

Supersedes #125 by @dustinhealy, whose root-cause analysis and inset ring
this reuses.
@danny-avila

Copy link
Copy Markdown
Contributor Author

@codex review

Pass 1. Head: 5d80069

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-27T08:40:35.221805Z 5d80069 Manual request
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

Reviewed commit: 5d8006961a

ℹ️ 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".

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