fix(a11y): descriptive aria-label on reaction buttons (P3-4)
Reaction.tsx now computes aria-label='{shortcode} reaction, N people'
using getShortcodeFor so screen readers announce emoji name and count
instead of an ambiguous button. Custom (mxc://) emoji falls back to
'custom emoji reaction'.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -184,7 +184,7 @@ This document tracks identified bugs, edge cases, and architectural discrepancie
|
|||||||
| Performance | Numerous event handlers (e.g., handleUserClick, handleReplyClick) lack `useCallback`, leading to unnecessary re-renders of message components. | `cinny/src/app/features/room/RoomTimeline.tsx` | OPEN |
|
| Performance | Numerous event handlers (e.g., handleUserClick, handleReplyClick) lack `useCallback`, leading to unnecessary re-renders of message components. | `cinny/src/app/features/room/RoomTimeline.tsx` | OPEN |
|
||||||
| Performance | The `submit` function and file handling callbacks (e.g., handleSendUpload) are re-created on every render, causing re-renders of the editor and toolbar components. | `cinny/src/app/features/room/RoomInput.tsx` | OPEN |
|
| Performance | The `submit` function and file handling callbacks (e.g., handleSendUpload) are re-created on every render, causing re-renders of the editor and toolbar components. | `cinny/src/app/features/room/RoomInput.tsx` | OPEN |
|
||||||
| Accessibility | `button` for edit history lacks `aria-label` | `cinny/src/app/components/message/content/FallbackContent.tsx` | FIXED ⚠️ UNTESTED — added `aria-label="View edit history"` |
|
| Accessibility | `button` for edit history lacks `aria-label` | `cinny/src/app/components/message/content/FallbackContent.tsx` | FIXED ⚠️ UNTESTED — added `aria-label="View edit history"` |
|
||||||
| Accessibility | `button` for reaction lacks `aria-label` | `cinny/src/app/components/message/Reaction.tsx` | OPEN — emoji content is already screen-reader-accessible via alt text; parent caller would need to set aria-label per reaction |
|
| Accessibility | `button` for reaction lacks `aria-label` | `cinny/src/app/components/message/Reaction.tsx` | **FIXED ⚠️ UNTESTED** — `Reaction` component now computes `aria-label="{shortcode} reaction, N people"` internally using `getShortcodeFor`; custom (mxc://) emoji falls back to "custom emoji reaction". |
|
||||||
| Accessibility | `button` for ThreadIndicator lacks `aria-label` | `cinny/src/app/components/message/Reply.tsx` | FIXED ⚠️ UNTESTED — added `aria-label="View thread"` |
|
| Accessibility | `button` for ThreadIndicator lacks `aria-label` | `cinny/src/app/components/message/Reply.tsx` | FIXED ⚠️ UNTESTED — added `aria-label="View thread"` |
|
||||||
| Accessibility | `button` for ReplyLayout lacks `aria-label` | `cinny/src/app/components/message/Reply.tsx` | FIXED ⚠️ UNTESTED — added `aria-label="Jump to original message"` |
|
| Accessibility | `button` for ReplyLayout lacks `aria-label` | `cinny/src/app/components/message/Reply.tsx` | FIXED ⚠️ UNTESTED — added `aria-label="Jump to original message"` |
|
||||||
|
|
||||||
|
|||||||
@@ -15,34 +15,42 @@ export const Reaction = as<
|
|||||||
reaction: string;
|
reaction: string;
|
||||||
useAuthentication?: boolean;
|
useAuthentication?: boolean;
|
||||||
}
|
}
|
||||||
>(({ className, mx, count, reaction, useAuthentication, ...props }, ref) => (
|
>(({ className, mx, count, reaction, useAuthentication, ...props }, ref) => {
|
||||||
<Box
|
const shortcode = reaction.startsWith('mxc://')
|
||||||
as="button"
|
? 'custom emoji'
|
||||||
className={classNames(css.Reaction, className)}
|
: (getShortcodeFor(getHexcodeForEmoji(reaction)) ?? reaction);
|
||||||
alignItems="Center"
|
const label = `${shortcode} reaction, ${count} ${count === 1 ? 'person' : 'people'}`;
|
||||||
shrink="No"
|
|
||||||
gap="200"
|
return (
|
||||||
{...props}
|
<Box
|
||||||
ref={ref}
|
as="button"
|
||||||
>
|
className={classNames(css.Reaction, className)}
|
||||||
<Text className={css.ReactionText} as="span" size="T400">
|
alignItems="Center"
|
||||||
{reaction.startsWith('mxc://') ? (
|
shrink="No"
|
||||||
<img
|
gap="200"
|
||||||
className={css.ReactionImg}
|
aria-label={label}
|
||||||
src={mxcUrlToHttp(mx, reaction, useAuthentication) ?? reaction}
|
{...props}
|
||||||
alt={reaction}
|
ref={ref}
|
||||||
/>
|
>
|
||||||
) : (
|
<Text className={css.ReactionText} as="span" size="T400">
|
||||||
<Text as="span" size="Inherit" truncate>
|
{reaction.startsWith('mxc://') ? (
|
||||||
{reaction}
|
<img
|
||||||
</Text>
|
className={css.ReactionImg}
|
||||||
)}
|
src={mxcUrlToHttp(mx, reaction, useAuthentication) ?? reaction}
|
||||||
</Text>
|
alt={reaction}
|
||||||
<Text as="span" size="T300">
|
/>
|
||||||
{count}
|
) : (
|
||||||
</Text>
|
<Text as="span" size="Inherit" truncate>
|
||||||
</Box>
|
{reaction}
|
||||||
));
|
</Text>
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
<Text as="span" size="T300">
|
||||||
|
{count}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
type ReactionTooltipMsgProps = {
|
type ReactionTooltipMsgProps = {
|
||||||
room: Room;
|
room: Room;
|
||||||
|
|||||||
Reference in New Issue
Block a user