👁️‍🗨️ fix: Replace Select with Menu in AccountSettings for Screen Reader Accuracy (#11980)
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Waiting to run
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Waiting to run
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Blocked by required conditions

AccountSettings was using Select, but it makes more sense (for a11y)
to use Menu. The Select has the wrong role & behavior for the purpose
of AccountSettings; the "listbox" role it uses is for selecting
values in a form.

Menu matches the actual content better for screen readers; the
"menu" role is more appropriate for selecting one of a number of links.
This commit is contained in:
Daniel Lew 2026-02-28 15:58:50 -06:00 committed by GitHub
parent 723acd830c
commit 0e5ee379b3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,5 +1,5 @@
import { useState, memo, useRef } from 'react';
import * as Select from '@ariakit/react/select';
import * as Menu from '@ariakit/react/menu';
import { FileText, LogOut } from 'lucide-react';
import { LinkIcon, GearIcon, DropdownMenuSeparator, Avatar } from '@librechat/client';
import { MyFilesModal } from '~/components/Chat/Input/Files/MyFilesModal';
@ -20,8 +20,8 @@ function AccountSettings() {
const accountSettingsButtonRef = useRef<HTMLButtonElement>(null);
return (
<Select.SelectProvider>
<Select.Select
<Menu.MenuProvider>
<Menu.MenuButton
ref={accountSettingsButtonRef}
aria-label={localize('com_nav_account_settings')}
data-testid="nav-user"
@ -38,8 +38,8 @@ function AccountSettings() {
>
{user?.name ?? user?.username ?? localize('com_nav_user')}
</div>
</Select.Select>
<Select.SelectPopover
</Menu.MenuButton>
<Menu.Menu
className="account-settings-popover popover-ui z-[125] w-[305px] rounded-lg md:w-[244px]"
style={{
transformOrigin: 'bottom',
@ -59,43 +59,29 @@ function AccountSettings() {
<DropdownMenuSeparator />
</>
)}
<Select.SelectItem
value=""
onClick={() => setShowFiles(true)}
className="select-item text-sm"
>
<Menu.MenuItem onClick={() => setShowFiles(true)} className="select-item text-sm">
<FileText className="icon-md" aria-hidden="true" />
{localize('com_nav_my_files')}
</Select.SelectItem>
</Menu.MenuItem>
{startupConfig?.helpAndFaqURL !== '/' && (
<Select.SelectItem
value=""
<Menu.MenuItem
onClick={() => window.open(startupConfig?.helpAndFaqURL, '_blank')}
className="select-item text-sm"
>
<LinkIcon aria-hidden="true" />
{localize('com_nav_help_faq')}
</Select.SelectItem>
</Menu.MenuItem>
)}
<Select.SelectItem
value=""
onClick={() => setShowSettings(true)}
className="select-item text-sm"
>
<Menu.MenuItem onClick={() => setShowSettings(true)} className="select-item text-sm">
<GearIcon className="icon-md" aria-hidden="true" />
{localize('com_nav_settings')}
</Select.SelectItem>
</Menu.MenuItem>
<DropdownMenuSeparator />
<Select.SelectItem
aria-selected={true}
onClick={() => logout()}
value="logout"
className="select-item text-sm"
>
<Menu.MenuItem onClick={() => logout()} className="select-item text-sm">
<LogOut className="icon-md" aria-hidden="true" />
{localize('com_nav_log_out')}
</Select.SelectItem>
</Select.SelectPopover>
</Menu.MenuItem>
</Menu.Menu>
{showFiles && (
<MyFilesModal
open={showFiles}
@ -104,7 +90,7 @@ function AccountSettings() {
/>
)}
{showSettings && <Settings open={showSettings} onOpenChange={setShowSettings} />}
</Select.SelectProvider>
</Menu.MenuProvider>
);
}