Skip to content

Commit 91a23d3

Browse files
feat(ux): add aria-labels and loading state to config table buttons
Co-authored-by: jmbish04 <26469722+jmbish04@users.noreply.github.com>
1 parent 8dd4d48 commit 91a23d3

2 files changed

Lines changed: 9 additions & 5 deletions

File tree

.Jules/palette.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
## 2024-05-18 - Icon-Only Button Accessibility in Config Table
3+
**Learning:** Config tables often rely heavily on icon-only buttons (like Edit/Save/Cancel) to save horizontal space, which frequently lack proper ARIA labels and tooltips, causing severe accessibility and usability issues for screen reader users and those navigating complex settings.
4+
**Action:** Always ensure icon-only buttons in dense data tables or lists include `aria-label` and `title` attributes. Additionally, include visual loading states directly within the button for async actions (like Save) to prevent user confusion.

src/frontend/src/components/config/ConfigTable.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
SelectTrigger,
1717
SelectValue,
1818
} from "@/components/ui/select";
19-
import { Pencil, Check, X, Eye, EyeOff } from "lucide-react";
19+
import { Pencil, Check, X, Eye, EyeOff, Loader2 } from "lucide-react";
2020

2121
export type ConfigFieldType = "string" | "number" | "boolean" | "secret";
2222

@@ -132,15 +132,15 @@ export function ConfigTable({ data, fields, onSave }: ConfigTableProps) {
132132
<TableCell className="text-right">
133133
{isEditing ? (
134134
<div className="flex justify-end gap-2">
135-
<Button size="icon" variant="ghost" onClick={() => handleSave(field.key, field.type)} disabled={isSaving}>
136-
<Check className="h-4 w-4 text-green-500" />
135+
<Button size="icon" variant="ghost" onClick={() => handleSave(field.key, field.type)} disabled={isSaving} aria-label="Save configuration" title="Save configuration">
136+
{isSaving ? <Loader2 className="h-4 w-4 animate-spin text-green-500" /> : <Check className="h-4 w-4 text-green-500" />}
137137
</Button>
138-
<Button size="icon" variant="ghost" onClick={handleCancel} disabled={isSaving}>
138+
<Button size="icon" variant="ghost" onClick={handleCancel} disabled={isSaving} aria-label="Cancel editing" title="Cancel editing">
139139
<X className="h-4 w-4 text-red-500" />
140140
</Button>
141141
</div>
142142
) : (
143-
<Button size="icon" variant="ghost" onClick={() => handleEdit(field.key, currentValue)}>
143+
<Button size="icon" variant="ghost" onClick={() => handleEdit(field.key, currentValue)} aria-label="Edit configuration" title="Edit configuration">
144144
<Pencil className="h-4 w-4" />
145145
</Button>
146146
)}

0 commit comments

Comments
 (0)