Skip to content

fix(ui): give icon-only controls a tooltip with their label - #497

Merged
ValentinKolb merged 1 commit into
mainfrom
fix/icon-tooltips
Oct 1, 2026
Merged

ValentinKolb merged 1 commit into
mainfrom
fix/icon-tooltips

Conversation

@ValentinKolb

Copy link
Copy Markdown
Collaborator

Outcome

Icon-only controls now show their label as the shared @k2b/ui tooltip, in English and German, instead of relying on a late native browser title. This covers the zoom in, zoom out, reset, and fullscreen controls over Mermaid diagrams and other ZoomPanViewport content, the same controls on interactive charts, and every IconButton, IconButtonLink, and icon-only Dropdown.Trigger across the apps.

  • Default tooltip: IconButton, IconButtonLink, and iconOnly Dropdown.Trigger show label (or an explicit title) as the tooltip. tooltip still overrides it; tooltip={false} still opts out. A control inside a Tooltip.Anchor leaves the hint to the anchor, so no target shows two tooltips (the existing anchor-wrapped buttons previously showed the anchor tooltip and a native title).
  • When it opens: on hover and on visible (keyboard) focus, after the usual 250 ms delay. Touch never opens one. Focus without a ring (after a click or tap, or focus a closing menu or dialog returns silently since fix(ui): return focus without a ring when a pointer opened the overlay #496) opens none, so default tooltips do not pop up after a menu closes.
  • Accessibility: the label stays the accessible name. A tooltip that only repeats the aria-label is no longer added as aria-describedby, so screen readers do not read the name twice. Hints that add information, such as Zoom in (+), still describe the control.
  • No-JavaScript fallback: server HTML keeps the label as a native title; hydration removes it.
  • Library controls: zoom-pan and chart controls, the chart explorer's clear button, split-button and filter-chip menus, chat composer and message actions, markdown editor tools, pane close/add, image rotate, and file-view actions switched from native titles to the shared tooltip.
  • Apps: icon-only Button/ButtonLink uses in Core (AI quota, SSH keys), Files shares, Grids (query parameters, custom app builder), and Spaces became IconButton/IconButtonLink. The Cloud preferences menu no longer opts out of its tooltip. The Gateway admin column link got a localized name (EN/DE).
  • Guard: the new icon-controls check fails on icon-only Button/ButtonLink (use the IconButton family) and on native icon-only button/a/Tooltip.Trigger without an accessible name.

Field affordances (clear, stepper, remove-chip), tab close, dialog close, and calendar arrows keep their accessible name without a hover hint. They are part of a composite control and are left unchanged here.

Layout

Tooltips are top-layer popovers. A closed tooltip is display: none and sits after its control, so :first-child tap-area rules and row layouts do not change. A real-browser check (Chromium, light mode, EN and DE) showed Zoom in (+) / Vergrößern (+) and Choose list view / Listenansicht wählen on hover, with no change to the control's box and no native title after hydration. A tap on a phone viewport left no tooltip open.

Verification

  • packages/ui/test/icon-tooltips.behavior.test.tsx covers: the label tooltip; no title or redundant description after hydration; hover opens it; touch and ring-less focus do not; keyboard focus does; explicit hints describe the control; tooltip={false} and Tooltip.Anchor give one hint; icon-only dropdown triggers and filter chips; and zoom-pan shortcut hints.
  • An SSR render test covers the server tooltip and title fallback. Existing render tests are updated for Panes, chat, and Spaces claim.
  • scripts/checks/icon-controls.test.ts covers the new rule.
  • bun run check (18/18), bun run test, and the @k2b/ui unit, render, and behavior suites pass.

Docs and skill

The UI context is updated: Tooltip (defaults, focus and touch behavior, description rule, SSR fallback), Buttons, Menus, and FilterChip. The cloud-dev skill is unchanged: it already tells authors to use @k2b/ui controls, and the per-component contract lives in the UI context.

Icon-only controls only carried a native title, which appears late, never
on keyboard focus, and not at all for some canvas controls such as the
zoom, reset, and fullscreen buttons over diagrams and charts. IconButton,
IconButtonLink, and icon-only Dropdown triggers now show their label as the
shared tooltip by default. The native title stays only in server HTML as the
no-JavaScript fallback and is removed on hydration, so a hint never appears
twice; a Tooltip.Anchor around a control keeps the only hint.

Tooltips now open on hover and on visible (keyboard) focus only. Touch never
opens one, and focus that a click, tap, or closing overlay returns without a
ring opens none, so a default tooltip does not pop up after a menu or dialog
closes. A tooltip that only repeats the accessible name is not added as a
second description.

@k2b/ui's own icon-only controls (zoom-pan and chart controls, chat,
markdown editor, panes, file views) and app buttons that rendered an icon
through Button now use the shared tooltip. The new icon-controls check
reports icon-only Button/ButtonLink and native icon-only controls without
an accessible name.
@ValentinKolb
ValentinKolb enabled auto-merge October 1, 2026 02:24
@ValentinKolb
ValentinKolb added this pull request to the merge queue Oct 1, 2026
Merged via the queue into main with commit f3119bc Oct 1, 2026
19 checks passed
@ValentinKolb
ValentinKolb deleted the fix/icon-tooltips branch October 1, 2026 02:47
@github-actions github-actions Bot mentioned this pull request Oct 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant