Skip to content

Commit 2cf7cdd

Browse files
authored
SelectPanel: Announce changes to screen readers (#3316)
* SelectPanel: Announce filter changes to screenreaders * Create rare-humans-watch.md * Update formatting
1 parent 00cf2e3 commit 2cf7cdd

File tree

2 files changed

+53
-35
lines changed

2 files changed

+53
-35
lines changed

.changeset/rare-humans-watch.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@primer/react": patch
3+
---
4+
5+
SelectPanel: Announce changes to screen readers

src/SelectPanel/SelectPanel.tsx

Lines changed: 48 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import {useId} from '../hooks/useId'
1+
import {SearchIcon} from '@primer/octicons-react'
22
import React, {useCallback, useMemo} from 'react'
33
import {AnchoredOverlay, AnchoredOverlayProps} from '../AnchoredOverlay'
44
import {AnchoredOverlayWrapperAnchorProps} from '../AnchoredOverlay/AnchoredOverlay'
5+
import Box from '../Box'
56
import {FilteredActionList, FilteredActionListProps} from '../FilteredActionList'
67
import Heading from '../Heading'
78
import {OverlayProps} from '../Overlay'
@@ -11,9 +12,9 @@ import {ItemInput} from '../deprecated/ActionList/List'
1112
import {DropdownButton} from '../deprecated/DropdownMenu'
1213
import {useProvidedRefOrCreate} from '../hooks'
1314
import {FocusZoneHookSettings} from '../hooks/useFocusZone'
15+
import {useId} from '../hooks/useId'
1416
import {useProvidedStateOrCreate} from '../hooks/useProvidedStateOrCreate'
15-
import Box from '../Box'
16-
import {SearchIcon} from '@primer/octicons-react'
17+
import {LiveRegion, LiveRegionOutlet, Message} from '../internal/components/LiveRegion'
1718

1819
interface SelectPanelSingleSelection {
1920
selected: ItemInput | undefined
@@ -160,39 +161,51 @@ export function SelectPanel({
160161
}, [inputLabel, textInputProps])
161162

162163
return (
163-
<AnchoredOverlay
164-
renderAnchor={renderMenuAnchor}
165-
anchorRef={anchorRef}
166-
open={open}
167-
onOpen={onOpen}
168-
onClose={onClose}
169-
overlayProps={{role: 'dialog', 'aria-labelledby': titleId, ...overlayProps}}
170-
focusTrapSettings={focusTrapSettings}
171-
focusZoneSettings={focusZoneSettings}
172-
>
173-
<Box sx={{display: 'flex', flexDirection: 'column', height: 'inherit', maxHeight: 'inherit'}}>
174-
<Box sx={{pt: 2, px: 3}}>
175-
<Heading as="h1" id={titleId} sx={{fontSize: 1}}>
176-
{title}
177-
</Heading>
178-
</Box>
179-
<FilteredActionList
180-
filterValue={filterValue}
181-
onFilterChange={onFilterChange}
182-
placeholderText={placeholderText}
183-
{...listProps}
184-
role="listbox"
185-
aria-multiselectable={isMultiSelectVariant(selected) ? 'true' : 'false'}
186-
selectionVariant={isMultiSelectVariant(selected) ? 'multiple' : 'single'}
187-
items={itemsToRender}
188-
textInputProps={extendedTextInputProps}
189-
inputRef={inputRef}
190-
// inheriting height and maxHeight ensures that the FilteredActionList is never taller
191-
// than the Overlay (which would break scrolling the items)
192-
sx={{...sx, height: 'inherit', maxHeight: 'inherit'}}
164+
<LiveRegion>
165+
<AnchoredOverlay
166+
renderAnchor={renderMenuAnchor}
167+
anchorRef={anchorRef}
168+
open={open}
169+
onOpen={onOpen}
170+
onClose={onClose}
171+
overlayProps={{role: 'dialog', 'aria-labelledby': titleId, ...overlayProps}}
172+
focusTrapSettings={focusTrapSettings}
173+
focusZoneSettings={focusZoneSettings}
174+
>
175+
<LiveRegionOutlet />
176+
<Message
177+
value={
178+
filterValue === ''
179+
? 'Showing all items'
180+
: items.length <= 0
181+
? 'No matching items'
182+
: `${items.length} matching ${items.length === 1 ? 'item' : 'items'}`
183+
}
193184
/>
194-
</Box>
195-
</AnchoredOverlay>
185+
<Box sx={{display: 'flex', flexDirection: 'column', height: 'inherit', maxHeight: 'inherit'}}>
186+
<Box sx={{pt: 2, px: 3}}>
187+
<Heading as="h1" id={titleId} sx={{fontSize: 1}}>
188+
{title}
189+
</Heading>
190+
</Box>
191+
<FilteredActionList
192+
filterValue={filterValue}
193+
onFilterChange={onFilterChange}
194+
placeholderText={placeholderText}
195+
{...listProps}
196+
role="listbox"
197+
aria-multiselectable={isMultiSelectVariant(selected) ? 'true' : 'false'}
198+
selectionVariant={isMultiSelectVariant(selected) ? 'multiple' : 'single'}
199+
items={itemsToRender}
200+
textInputProps={extendedTextInputProps}
201+
inputRef={inputRef}
202+
// inheriting height and maxHeight ensures that the FilteredActionList is never taller
203+
// than the Overlay (which would break scrolling the items)
204+
sx={{...sx, height: 'inherit', maxHeight: 'inherit'}}
205+
/>
206+
</Box>
207+
</AnchoredOverlay>
208+
</LiveRegion>
196209
)
197210
}
198211

0 commit comments

Comments
 (0)