From ffcca3254edda7e2c8cf81f5e8ee67a7fdf8d75c Mon Sep 17 00:00:00 2001 From: Daniel Lew Date: Tue, 25 Nov 2025 12:56:32 -0600 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=A2=20fix:=20Remove=20Side=20Panel=20E?= =?UTF-8?q?lements=20from=20Screen=20Reader=20when=20Hidden=20(#10648)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: remove side panel elements from screen reader when hidden There's both left & right side panels; elements of both of them are hidden when dismissed. However, currently they are being hidden by using classes to hide their UI (such as making the sidebar zero width). That works for visually dismissing these elements, but they can still be viewed by a screen reader (using the tab key to jump between interactable elements). That can be a rather confusing experience for anyone visually impaired (such as duplicate buttons, or buttons that do nothing). -------- I've changed it so hidden elements are fully removed from the render. This prevents them from being interactable via keyboard. I leveraged Motion to duplicate the animations as they happened before. I subtly cleaned up the animations while I was at it. * Implemented reasonable suggestions from Copilot review --- client/src/components/Chat/Header.tsx | 37 +++++++++--------- client/src/components/Nav/MobileNav.tsx | 4 +- client/src/components/Nav/Nav.tsx | 38 +++++++++---------- .../components/SidePanel/SidePanelGroup.tsx | 12 +++--- client/src/routes/Root.tsx | 2 +- 5 files changed, 49 insertions(+), 44 deletions(-) diff --git a/client/src/components/Chat/Header.tsx b/client/src/components/Chat/Header.tsx index bf04a2e4f3..5025307020 100644 --- a/client/src/components/Chat/Header.tsx +++ b/client/src/components/Chat/Header.tsx @@ -11,6 +11,7 @@ import BookmarkMenu from './Menus/BookmarkMenu'; import { TemporaryChat } from './TemporaryChat'; import AddMultiConvo from './AddMultiConvo'; import { useHasAccess } from '~/hooks'; +import { AnimatePresence, motion } from 'framer-motion'; const defaultInterface = getConfigDefaults().interface; @@ -38,24 +39,24 @@ export default function Header() { return (
-
-
- - -
-
+
+ + {!navVisible && ( + + + + + )} + + +
{interfaceConfig.presets === true && interfaceConfig.modelSelect && } {hasAccessToBookmarks === true && } diff --git a/client/src/components/Nav/MobileNav.tsx b/client/src/components/Nav/MobileNav.tsx index 6f11b327ce..7a508a28eb 100644 --- a/client/src/components/Nav/MobileNav.tsx +++ b/client/src/components/Nav/MobileNav.tsx @@ -9,8 +9,10 @@ import { clearMessagesCache } from '~/utils'; import store from '~/store'; export default function MobileNav({ + navVisible, setNavVisible, }: { + navVisible: boolean; setNavVisible: Dispatch>; }) { const localize = useLocalize(); @@ -25,7 +27,7 @@ export default function MobileNav({ type="button" data-testid="mobile-header-new-chat-button" aria-label={localize('com_nav_open_sidebar')} - className="m-1 inline-flex size-10 items-center justify-center rounded-full hover:bg-surface-hover" + className={`m-1 inline-flex size-10 items-center justify-center rounded-full hover:bg-surface-hover ${navVisible ? 'invisible' : ''}`} onClick={() => setNavVisible((prev) => { localStorage.setItem('navVisible', JSON.stringify(!prev)); diff --git a/client/src/components/Nav/Nav.tsx b/client/src/components/Nav/Nav.tsx index ecea9c3d14..e449904143 100644 --- a/client/src/components/Nav/Nav.tsx +++ b/client/src/components/Nav/Nav.tsx @@ -1,5 +1,6 @@ import { useCallback, useEffect, useState, useMemo, memo, lazy, Suspense, useRef } from 'react'; import { useRecoilValue } from 'recoil'; +import { AnimatePresence, motion } from 'framer-motion'; import { useMediaQuery } from '@librechat/client'; import { PermissionTypes, Permissions } from 'librechat-data-provider'; import type { ConversationListResponse } from 'librechat-data-provider'; @@ -190,22 +191,21 @@ const Nav = memo( return ( <> -
-
-
-
+ + {navVisible && ( + +
-
-
-
+ + )} + {isSmallScreen && } ); diff --git a/client/src/components/SidePanel/SidePanelGroup.tsx b/client/src/components/SidePanel/SidePanelGroup.tsx index 5a81f088df..14473127b5 100644 --- a/client/src/components/SidePanel/SidePanelGroup.tsx +++ b/client/src/components/SidePanel/SidePanelGroup.tsx @@ -147,11 +147,13 @@ const SidePanelGroup = memo( {artifacts != null && isSmallScreen && (
{artifacts}
)} -