🔇 fix: Hide Button Icons from Screen Readers (#10776)
Some checks failed
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Has been cancelled
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Has been cancelled

If you've got a screen reader that is reading out the whole page,
each icon button (i.e., `<button><SVG></button>`) will have both
the button's aria-label read out as well as the title from the
SVG (which is usually just "image").

Since we are pretty good about setting aria-labels, we should instead
use `aria-hidden="true"` on these images, since they are not useful
to be read out.

I don't consider this a comprehensive review of all icons in the app,
but I knocked out all the low hanging fruit in this commit.
This commit is contained in:
Daniel Lew 2025-12-11 15:35:17 -06:00 committed by GitHub
parent b288d81f5a
commit 1143f73f59
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
175 changed files with 340 additions and 183 deletions

View file

@ -133,7 +133,7 @@ function ConvoOptions({
{
label: localize('com_ui_share'),
onClick: handleShareClick,
icon: <Share2 className="icon-sm mr-2 text-text-primary" />,
icon: <Share2 className="icon-sm mr-2 text-text-primary" aria-hidden="true" />,
show: startupConfig && startupConfig.sharedLinksEnabled,
hideOnClick: false,
ref: shareButtonRef,
@ -142,7 +142,7 @@ function ConvoOptions({
{
label: localize('com_ui_rename'),
onClick: renameHandler,
icon: <Pen className="icon-sm mr-2 text-text-primary" />,
icon: <Pen className="icon-sm mr-2 text-text-primary" aria-hidden="true" />,
},
{
label: localize('com_ui_duplicate'),
@ -151,7 +151,7 @@ function ConvoOptions({
icon: isDuplicateLoading ? (
<Spinner className="size-4" />
) : (
<CopyPlus className="icon-sm mr-2 text-text-primary" />
<CopyPlus className="icon-sm mr-2 text-text-primary" aria-hidden="true" />
),
},
{
@ -161,13 +161,13 @@ function ConvoOptions({
icon: isArchiveLoading ? (
<Spinner className="size-4" />
) : (
<Archive className="icon-sm mr-2 text-text-primary" />
<Archive className="icon-sm mr-2 text-text-primary" aria-hidden="true" />
),
},
{
label: localize('com_ui_delete'),
onClick: handleDeleteClick,
icon: <Trash className="icon-sm mr-2 text-text-primary" />,
icon: <Trash className="icon-sm mr-2 text-text-primary" aria-hidden="true" />,
hideOnClick: false,
ref: deleteButtonRef,
render: (props) => <button {...props} />,

View file

@ -102,7 +102,11 @@ export default function ShareButton({
}}
className={cn('shrink-0', isCopying ? 'cursor-default' : '')}
>
{isCopying ? <CopyCheck className="size-4" /> : <Copy className="size-4" />}
{isCopying ? (
<CopyCheck className="size-4" aria-hidden="true" />
) : (
<Copy className="size-4" aria-hidden="true" />
)}
</Button>
</div>
)}

View file

@ -139,7 +139,7 @@ export default function SharedLinkButton({
{isUpdateLoading ? (
<Spinner className="size-4" />
) : (
<RotateCw className="size-4" />
<RotateCw className="size-4" aria-hidden="true" />
)}
</Button>
)}
@ -154,7 +154,7 @@ export default function SharedLinkButton({
variant="outline"
aria-label={qrCodeLabel}
>
<QrCode className="size-4" />
<QrCode className="size-4" aria-hidden="true" />
</Button>
)}
/>
@ -168,7 +168,7 @@ export default function SharedLinkButton({
variant="destructive"
aria-label={localize('com_ui_delete')}
>
<Trash2 className="size-4" />
<Trash2 className="size-4" aria-hidden="true" />
</Button>
)}
/>