🦻 fix: Standardize Message Aria Labels for Assistive Technology (#10796)

Message aria labels were using the format `message-{depth}-{id}`, which
reads out in a very unfriendly way to a screen reader (e.g.
"message-3-65a38d32-4d6e-42c7-b67b-9ee62f8cedb1").

I standardized all the labeling in one place (`getMessageAriaLabel()`).
They now read out "Message 1", "Message 2", and so on.
This commit is contained in:
Daniel Lew 2025-12-11 15:28:21 -06:00 committed by Danny Avila
parent 304bba853c
commit ad733157d7
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956
4 changed files with 18 additions and 8 deletions

View file

@ -11,7 +11,7 @@ import SiblingSwitch from './SiblingSwitch';
import MultiMessage from './MultiMessage';
import HoverButtons from './HoverButtons';
import SubRow from './SubRow';
import { cn } from '~/utils';
import { cn, getMessageAriaLabel } from '~/utils';
import store from '~/store';
export default function Message(props: TMessageProps) {
@ -96,7 +96,7 @@ export default function Message(props: TMessageProps) {
<div className="m-auto justify-center p-4 py-2 md:gap-6">
<div
id={messageId ?? ''}
aria-label={`message-${message.depth}-${messageId}`}
aria-label={getMessageAriaLabel(message, localize)}
className={cn(baseClasses.common, baseClasses.chat, 'message-render')}
>
<div className="relative flex flex-shrink-0 flex-col items-center">

View file

@ -11,8 +11,8 @@ import MessageIcon from '~/components/Chat/Messages/MessageIcon';
import SubRow from '~/components/Chat/Messages/SubRow';
import { fontSizeAtom } from '~/store/fontSize';
import { MessageContext } from '~/Providers';
import { useMessageActions } from '~/hooks';
import { cn, logger } from '~/utils';
import { useLocalize, useMessageActions } from '~/hooks';
import { cn, getMessageAriaLabel, logger } from '~/utils';
import store from '~/store';
type MessageRenderProps = {
@ -37,6 +37,7 @@ const MessageRender = memo(
setCurrentEditId,
isSubmittingFamily = false,
}: MessageRenderProps) => {
const localize = useLocalize();
const {
ask,
edit,
@ -130,7 +131,7 @@ const MessageRender = memo(
return (
<div
id={msg.messageId}
aria-label={`message-${msg.depth}-${msg.messageId}`}
aria-label={getMessageAriaLabel(msg, localize)}
className={cn(
baseClasses.common,
isCard ? baseClasses.card : baseClasses.chat,

View file

@ -8,10 +8,10 @@ import PlaceholderRow from '~/components/Chat/Messages/ui/PlaceholderRow';
import SiblingSwitch from '~/components/Chat/Messages/SiblingSwitch';
import HoverButtons from '~/components/Chat/Messages/HoverButtons';
import MessageIcon from '~/components/Chat/Messages/MessageIcon';
import { useAttachments, useMessageActions } from '~/hooks';
import { useAttachments, useLocalize, useMessageActions } from '~/hooks';
import SubRow from '~/components/Chat/Messages/SubRow';
import { fontSizeAtom } from '~/store/fontSize';
import { cn, logger } from '~/utils';
import { cn, getMessageAriaLabel, logger } from '~/utils';
import store from '~/store';
type ContentRenderProps = {
@ -36,6 +36,7 @@ const ContentRender = memo(
setCurrentEditId,
isSubmittingFamily = false,
}: ContentRenderProps) => {
const localize = useLocalize();
const { attachments, searchResults } = useAttachments({
messageId: msg?.messageId,
attachments: msg?.attachments,
@ -130,7 +131,7 @@ const ContentRender = memo(
return (
<div
id={msg.messageId}
aria-label={`message-${msg.depth}-${msg.messageId}`}
aria-label={getMessageAriaLabel(msg, localize)}
className={cn(
baseClasses.common,
isCard ? baseClasses.card : baseClasses.chat,

View file

@ -1,6 +1,8 @@
import { ContentTypes, QueryKeys, Constants } from 'librechat-data-provider';
import type { TMessage, TMessageContentParts } from 'librechat-data-provider';
import type { QueryClient } from '@tanstack/react-query';
import type { LocalizeFunction } from '~/common';
import _ from 'lodash';
export const TEXT_KEY_DIVIDER = '|||';
@ -170,3 +172,9 @@ export const clearMessagesCache = (
queryClient.setQueryData<TMessage[]>([QueryKeys.messages, Constants.NEW_CONVO], []);
}
};
export const getMessageAriaLabel = (message: TMessage, localize: LocalizeFunction): string => {
return !_.isNil(message.depth)
? localize('com_endpoint_message_new', { 0: message.depth + 1 })
: localize('com_endpoint_message');
};