Skip to content

Commit 73c27bb

Browse files
fix(frontend): add accessible names to icon-only buttons (#2504)
* fix(frontend): add accessible names to icon-only buttons Icon-only buttons (refresh, delete ACL, open user actions, go back, clear filter, refresh topics/tasks) were announced as a bare 'button' to screen readers (WCAG 4.1.2 Name, Role, Value). Add aria-label to the cited sites in transcripts, security tabs, shadow links, and rp-connect, matching the existing sr-only/aria-label precedent (audit A11Y-02). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): give per-row icon buttons unique accessible names Address @claude review: the Delete ACL and user-actions buttons render once per table row with an identical aria-label, so screen-reader users can't tell which principal each targets. Include the principal/user name, matching the roles-tab.tsx convention (`Delete role ${entry.name}`). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 0fc0cbb commit 73c27bb

6 files changed

Lines changed: 32 additions & 6 deletions

File tree

frontend/src/components/pages/rp-connect/pipeline/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -984,7 +984,7 @@ function PipelinePageContent() {
984984
) : null}
985985
{mode === 'view' && !pipeline ? (
986986
<div className="flex items-center gap-2">
987-
<Button className="-ml-3.5 shrink-0" onClick={handleCancel} size="icon" variant="ghost">
987+
<Button aria-label="Go back" className="-ml-3.5 shrink-0" onClick={handleCancel} size="icon" variant="ghost">
988988
<ArrowLeftIcon className="h-5 w-5" />
989989
</Button>
990990
<Skeleton variant="text" width="md" />

frontend/src/components/pages/security/tabs/acls-tab.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,13 @@ const AclsTabContent: FC = () => {
214214
return (
215215
<DropdownMenu>
216216
<DropdownMenuTrigger asChild>
217-
<Button className="deleteButton" onClick={() => {}} size="icon-sm" variant="destructive-ghost">
217+
<Button
218+
aria-label={`Delete ACL for ${record.principalName}`}
219+
className="deleteButton"
220+
onClick={() => {}}
221+
size="icon-sm"
222+
variant="destructive-ghost"
223+
>
218224
<TrashIcon className="h-4 w-4" />
219225
</Button>
220226
</DropdownMenuTrigger>

frontend/src/components/pages/security/tabs/users-tab.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ const UserActions = ({ user }: { user: PrincipalEntry }) => {
251251
<DropdownMenu>
252252
<DropdownMenuTrigger asChild>
253253
<Button asChild className="deleteButton" size="icon-sm" variant="ghost">
254-
<button type="button">
254+
<button aria-label={`Open actions for ${user.name}`} type="button">
255255
<MoreHorizontalIcon className="h-4 w-4" />
256256
</button>
257257
</Button>

frontend/src/components/pages/shadowlinks/details/shadow-topics-table.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,17 @@ export const ShadowTopicsTable: React.FC<ShadowTopicsTableProps> = ({
229229
/>
230230
</div>
231231
{Boolean(topicNameFilter) && (
232-
<Button onClick={() => onTopicNameFilterChange?.('')} size="sm" variant="ghost">
232+
<Button
233+
aria-label="Clear filter"
234+
onClick={() => onTopicNameFilterChange?.('')}
235+
size="sm"
236+
variant="ghost"
237+
>
233238
<X className="h-4 w-4" />
234239
</Button>
235240
)}
236241
<Button
242+
aria-label="Refresh topics"
237243
data-testid="refresh-topics-button"
238244
disabled={isFetching}
239245
onClick={onRefresh}

frontend/src/components/pages/shadowlinks/details/tasks-table.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,14 @@ export const TasksTable = ({ tasks, onRefresh, dataUnavailable }: TasksTableProp
7575
<CardTitle>Tasks</CardTitle>
7676
{Boolean(onRefresh) && (
7777
<CardAction>
78-
<Button data-testid="refresh-tasks-button" onClick={onRefresh} size="icon" type="button" variant="ghost">
78+
<Button
79+
aria-label="Refresh tasks"
80+
data-testid="refresh-tasks-button"
81+
onClick={onRefresh}
82+
size="icon"
83+
type="button"
84+
variant="ghost"
85+
>
7986
<RefreshCw className="h-5 w-5" />
8087
</Button>
8188
</CardAction>

frontend/src/components/pages/transcripts/components/transcript-filter-bar.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,14 @@ export const TranscriptFilterBar: FC<TranscriptFilterBarProps> = ({
427427
</Select>
428428

429429
{/* Refresh button */}
430-
<Button className="h-8 w-8" disabled={isLoading} onClick={onRefresh} size="icon" variant="outline">
430+
<Button
431+
aria-label="Refresh"
432+
className="h-8 w-8"
433+
disabled={isLoading}
434+
onClick={onRefresh}
435+
size="icon"
436+
variant="outline"
437+
>
431438
<RefreshCw className={`h-3.5 w-3.5 ${isLoading ? 'animate-spin' : ''}`} />
432439
</Button>
433440
</div>

0 commit comments

Comments
 (0)