Skip to content

Commit 78d5b27

Browse files
committed
fix: a11y: add aria-posinset for virtualized
For `react-virtualized` lists. [From MDN](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-posinset): > The aria-posinset attribute defines an element's number or position > in the current set of listitems or treeitems > when not all items are present in the DOM. TODO: - Make sure screen readers actually announce these. See TODO comment. - Apply to the remaining `<li`s.
1 parent e47255e commit 78d5b27

File tree

3 files changed

+37
-5
lines changed

3 files changed

+37
-5
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88

99
- keep the order of contacts when calling getContactsByIds #4651
1010

11+
### Fixed
12+
- accessibility: fix screen readers announcing incorrect list sizes
13+
1114
<a id="1_54_0"></a>
1215

1316
## [1.54.0] - 2025-02-15

packages/frontend/src/components/chat/ChatListItemRow.tsx

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,16 @@ export const ChatListItemRowChat = React.memo<{
5757
const chatId = chatListIds[index]
5858

5959
return (
60-
<li style={style}>
60+
<li
61+
style={style}
62+
// TODO looks like screen-readers (at least NVDA) do not announce
63+
// this "position" thing. Probably because the `<li>` itself
64+
// is not focusable.
65+
// Should we apply these attributes to the button?
66+
// And get rid of the wrapper `<li>` entirely?
67+
aria-posinset={index + 1}
68+
aria-setsize={chatListIds.length}
69+
>
6170
<ChatListItem
6271
isSelected={selectedChatId === chatId}
6372
chatListItem={chatCache[chatId] || undefined}
@@ -98,7 +107,11 @@ export const ChatListItemRowContact = React.memo<{
98107
}}
99108
/>
100109
) : (
101-
<li style={style}>
110+
<li
111+
style={style}
112+
aria-posinset={index + 1}
113+
aria-setsize={contactIds.length}
114+
>
102115
<PlaceholderChatListItem />
103116
</li>
104117
)
@@ -116,7 +129,11 @@ export const ChatListItemRowMessage = React.memo<{
116129
const accountId = selectedAccountId()
117130

118131
return (
119-
<li style={style}>
132+
<li
133+
style={style}
134+
aria-posinset={index + 1}
135+
aria-setsize={messageResultIds.length}
136+
>
120137
{messageSearchResult ? (
121138
<ChatListItemMessageResult
122139
queryStr={queryStr || ''}

packages/frontend/src/components/dialogs/AddMember/AddMemberInnerDialog.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,9 @@ function AddMemberInnerDialogRow({
323323
queryStrIsValidEmail,
324324
} = data
325325

326+
// `+1` for the "extra item" thing
327+
const ariaSetsize = contactIds.length + 1
328+
326329
const renderAddContact = () => {
327330
if (queryStrIsValidEmail) {
328331
const pseudoContact: Type.Contact = {
@@ -358,7 +361,7 @@ function AddMemberInnerDialogRow({
358361
)
359362
} else {
360363
return (
361-
<li style={style}>
364+
<li style={style} aria-posinset={index + 1} aria-setsize={ariaSetsize}>
362365
<PseudoListItemAddContact
363366
queryStr={queryStr}
364367
queryStrIsEmail={false}
@@ -376,13 +379,22 @@ function AddMemberInnerDialogRow({
376379
const contact = contactCache[contactIds[index]]
377380
if (!contact) {
378381
// Not loaded yet
379-
return <li style={style}></li>
382+
return (
383+
<li
384+
style={style}
385+
aria-posinset={index + 1}
386+
aria-setsize={ariaSetsize}
387+
></li>
388+
)
380389
}
381390

382391
return (
383392
<ContactListItem
384393
tagName='li'
385394
style={style}
395+
// TODO does this get applied to the underlying element?
396+
aria-posinset={index + 1}
397+
aria-setsize={ariaSetsize}
386398
contact={contact}
387399
showCheckbox
388400
checked={

0 commit comments

Comments
 (0)