UX/a11y: icon-only buttons missing a hover tooltip and aria-label (inconsistent across the UI)
#16,401 opened on Jun 1, 2026
Description
Summary
Several icon-only buttons across the UI (a KsButton/KsIconButton showing only an icon, with no visible label) have no tooltip on hover and no aria-label/title. The user has to guess what they do, and screen readers announce nothing.
This is both a UX problem (the action is not discoverable) and an accessibility problem. The design-system rule already mandates the fix but it isn't enforced uniformly.
From
ui/AGENTS.md: "Every icon-onlyKsIconButtonmust have an accessible label (aria-labelortitle). Screen readers do not see the icon glyph."
This is inconsistent, not absent
The behavior already exists on many buttons — it's just not uniform. Some components do it right, others don't, and in at least one file (FileExplorer.vue) some buttons in the same component are correctly wrapped while another is not.
Examples that already do it correctly (the desired pattern):
components/kv/KVTable.vue—:tooltip="$t(...)"on copy/edit/delete iconscomponents/secrets/SecretsTable.vue—:tooltip="$t(...)"components/executions/Logs.vue—:tooltip="$t(...)"on download/copy/refreshcomponents/layout/SidebarToggleButton.vue—aria-label="..."components/layout/NavBarActionsDropdown.vue—:ariaLabel="$t('actions')"
Examples missing it (audited on ui/src, line numbers approximate):
| # | File | Icon | Action | Suggested label |
|---|---|---|---|---|
| 1 | components/layout/HamburgerDropdown.vue |
DotsVertical | Opens the actions menu | More actions |
| 2 | components/layout/Collapse.vue |
Menu | Collapse/expand navigation | Toggle menu |
| 3 | components/MultiPanelTabs.vue |
DotsVertical | Panel actions (move/merge) | Panel actions |
| 4 | components/flows/FlowPlayground.vue |
DotsVertical | Playground actions (clear/disable) | Playground actions |
| 5 | components/executions/Executions.vue |
DotsVertical | Bulk actions on executions | Bulk actions |
| 6 | components/executions/TaskRunLine.vue |
DotsVertical | Task run actions | Actions — currently has an empty title="", which is worse than none |
| 7 | components/executions/MetricsTable.vue |
ChartAreaspline | Link to the metrics dashboard | View metrics |
| 8 | components/inputs/FileExplorer.vue |
PlusBox | File/folder import menu | Import |
| 9 | components/inputs/InputsForm.vue |
DeleteOutline | Remove an array item | Remove this item |
| 10 | components/labels/LabelInput.vue |
Plus / Minus | Add / remove a label | Add a label / Remove |
| 11 | components/admin/stats/Usages.vue |
TextSearchVariant | Navigate to search/filter | Search |
Note: this surfaced from the Audit Logs diff button (EE,
VectorDifferenceicon) which has the same issue — the pattern is shared, but only the OSS occurrences are tracked here.
Proposal
For each icon-only button without a visible label, add at minimum a tooltip on hover plus an accessible label:
KsIconButton→ set:tooltip="$t(...)"(and/or:ariaLabel), orKsButtonicon → wrap in<KsTooltip>and add anaria-label.
Use a short, explicit label (see the "Suggested label" column). For the recurring DotsVertical kebab menus, a shared convention (e.g. tooltip + standard aria-label "More actions") would keep things consistent.
Follow-up (optional, larger scope)
To stop the drift from recurring, consider a lint/check that flags a KsButton/KsIconButton with an icon and no text content unless it has a tooltip/aria-label/title.
Acceptance criteria
- Every icon-only button listed above has a hover tooltip and an
aria-label/title. - The empty
title=""inTaskRunLine.vueis replaced with a real label. - New strings go through
t()and are added toen.json.