️(frontend) focus side panel container on open

Focus aside on side panel open so screen readers announce the aria-label
This commit is contained in:
Cyril
2026-06-29 11:48:46 +02:00
committed by lebaudantoine
parent e910b1f0b7
commit ba6a4e971f
2 changed files with 123 additions and 93 deletions
+1
View File
@@ -29,6 +29,7 @@ and this project adheres to
- 🩹(backend) identify externally provisioned users to PostHog - 🩹(backend) identify externally provisioned users to PostHog
- 🐛(backend) fix info panel crash for unregistered rooms - 🐛(backend) fix info panel crash for unregistered rooms
- ♿️(frontend) focus side panel container on open #1452
## [1.23.0] - 2026-07-08 ## [1.23.0] - 2026-07-08
@@ -6,8 +6,8 @@ import { Button, Div } from '@/primitives'
import { RiArrowLeftLine, RiCloseLine } from '@remixicon/react' import { RiArrowLeftLine, RiCloseLine } from '@remixicon/react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { ParticipantsList } from './controls/Participants/ParticipantsList' import { ParticipantsList } from './controls/Participants/ParticipantsList'
import { useSidePanel } from '../hooks/useSidePanel' import { PanelId, useSidePanel } from '../hooks/useSidePanel'
import { ReactNode } from 'react' import React, { ReactNode, useCallback, useRef } from 'react'
import { Chat } from '../prefabs/Chat' import { Chat } from '../prefabs/Chat'
import { Effects } from './effects/Effects' import { Effects } from './effects/Effects'
import { Admin } from './Admin' import { Admin } from './Admin'
@@ -15,6 +15,7 @@ import { Tools } from './Tools'
import { Info } from './Info' import { Info } from './Info'
import { HStack } from '@/styled-system/jsx' import { HStack } from '@/styled-system/jsx'
import { useReactionsToolbar } from '@/features/reactions/hooks/useReactionsToolbar' import { useReactionsToolbar } from '@/features/reactions/hooks/useReactionsToolbar'
import { useRestoreFocus } from '@/hooks/useRestoreFocus'
type StyledSidePanelProps = { type StyledSidePanelProps = {
title: string title: string
@@ -29,7 +30,9 @@ type StyledSidePanelProps = {
isReactionToolbarOpen?: boolean isReactionToolbarOpen?: boolean
} }
const StyledSidePanel = ({ const StyledSidePanel = React.forwardRef<HTMLElement, StyledSidePanelProps>(
(
{
title, title,
ariaLabel, ariaLabel,
children, children,
@@ -40,8 +43,12 @@ const StyledSidePanel = ({
isSubmenu = false, isSubmenu = false,
onBack, onBack,
backButtonLabel, backButtonLabel,
}: StyledSidePanelProps) => ( },
ref
) => (
<aside <aside
ref={ref}
tabIndex={-1}
className={css({ className={css({
borderWidth: '1px', borderWidth: '1px',
borderStyle: 'solid', borderStyle: 'solid',
@@ -63,6 +70,9 @@ const StyledSidePanel = ({
top: 0, top: 0,
width: 'var(--sizes-room-side-panel)', width: 'var(--sizes-room-side-panel)',
transition: '.5s cubic-bezier(.4,0,.2,1) 5ms', transition: '.5s cubic-bezier(.4,0,.2,1) 5ms',
'&:focus': {
outline: 'none',
},
})} })}
style={{ style={{
transform: isClosed transform: isClosed
@@ -125,6 +135,9 @@ const StyledSidePanel = ({
{children} {children}
</aside> </aside>
) )
)
StyledSidePanel.displayName = 'StyledSidePanel'
type PanelProps = { type PanelProps = {
isOpen: boolean isOpen: boolean
@@ -162,8 +175,24 @@ export const SidePanel = () => {
const { isOpen: isReactionToolbarOpen } = useReactionsToolbar() const { isOpen: isReactionToolbarOpen } = useReactionsToolbar()
const asideRef = useRef<HTMLElement>(null)
const panelManagesFocus = activePanelId === PanelId.CHAT
const focusAside = useCallback(() => {
requestAnimationFrame(() => {
asideRef.current?.focus({ preventScroll: true })
})
}, [])
useRestoreFocus(isSidePanelOpen && !panelManagesFocus, {
onOpened: focusAside,
preventScroll: true,
})
return ( return (
<StyledSidePanel <StyledSidePanel
ref={asideRef}
title={title} title={title}
ariaLabel={t('ariaLabel', { title })} ariaLabel={t('ariaLabel', { title })}
onClose={() => { onClose={() => {