Tooltips: replace the native title attribute with nldd-tooltip #197

Closed
opened 2026-07-26 09:10:32 +00:00 by robbertbos · 0 comments
Owner

Waggle uses the native title attribute for tooltips in 40 places and nldd-tooltip in none. That is an accessibility gap rather than a styling one: a native title never appears on keyboard focus, is unreachable on touch, has a ~1s delay we cannot tune, and is announced inconsistently by screen readers.

Measured on the current main (counts are per element, not per file).

1. title duplicates aria-label — 11 elements

The same string appears twice on one element. The tooltip adds nothing, and a screen reader can end up announcing the accessible name twice.

  • components/cards/CardRow.vue (4)
  • components/cards/CardDetailsModal.vue (2)
  • components/composer/EmojiPicker.vue (2)
  • components/attachments/AttachmentPreview.vue, HtmlPreviewModal.vue, PdfPreviewModal.vue (1 each)

Fix: drop the title. No component needed.

2. title says something different from aria-label — 4 elements

Two different strings on one element, so what a mouse user sees and what a screen reader hears diverge.

Element aria-label title
AttachmentPreview.vue {naam} downloaden Downloaden
CardDetailsModal.vue Afbeelding {naam} vergroten {naam}
BubbleMenuButton.vue Bubble up triggerTitle
SendButton.vue Inplannen voor later reason why the button is disabled

SendButton is the interesting one: the title carries why the button is disabled ("Schrijf eerst een bericht"). That is exactly the information a keyboard user never gets today, because a disabled control cannot be hovered and title does not fire on focus.

Fix: decide per case whether the text is a name (belongs in aria-label) or a description (belongs in a tooltip with aria-describedby).

3. Genuine tooltips, title only — 22 elements

  • components/scheduling/QueuedRow.vue (5)
  • components/attachments/HtmlPreviewModal.vue (3), PdfPreviewModal.vue (3)
  • components/scheduling/ScheduledStripModal.vue (3)
  • components/cards/MmSourceBreadcrumb.vue (2)
  • CardRow.vue, ImageLightbox.vue, ReplyComposer.vue, SendButton.vue, DraftBadge.vue, DevUserSwitcher.vue (1 each)

Fix: nldd-tooltip. It wraps the child with display: contents so layout is untouched, shows on hover and focus, suppresses itself on touch, sets aria-describedby itself, and takes placement and timing (instant / default / never).

Why this is its own issue

Split off from #181 deliberately. That one is about typography and design tokens; this changes behaviour - focus, touch, and what a screen reader announces - so it wants its own pass with a keyboard and a screen reader, and a judgement per element on whether the text is essential or decorative.

Waggle uses the native `title` attribute for tooltips in 40 places and `nldd-tooltip` in none. That is an accessibility gap rather than a styling one: a native `title` never appears on keyboard focus, is unreachable on touch, has a ~1s delay we cannot tune, and is announced inconsistently by screen readers. Measured on the current `main` (counts are per element, not per file). ## 1. `title` duplicates `aria-label` — 11 elements The same string appears twice on one element. The tooltip adds nothing, and a screen reader can end up announcing the accessible name twice. - `components/cards/CardRow.vue` (4) - `components/cards/CardDetailsModal.vue` (2) - `components/composer/EmojiPicker.vue` (2) - `components/attachments/AttachmentPreview.vue`, `HtmlPreviewModal.vue`, `PdfPreviewModal.vue` (1 each) Fix: drop the `title`. No component needed. ## 2. `title` says something different from `aria-label` — 4 elements Two different strings on one element, so what a mouse user sees and what a screen reader hears diverge. | Element | `aria-label` | `title` | | --- | --- | --- | | `AttachmentPreview.vue` | `{naam} downloaden` | `Downloaden` | | `CardDetailsModal.vue` | `Afbeelding {naam} vergroten` | `{naam}` | | `BubbleMenuButton.vue` | `Bubble up` | `triggerTitle` | | `SendButton.vue` | `Inplannen voor later` | reason why the button is disabled | `SendButton` is the interesting one: the title carries *why* the button is disabled ("Schrijf eerst een bericht"). That is exactly the information a keyboard user never gets today, because a disabled control cannot be hovered and `title` does not fire on focus. Fix: decide per case whether the text is a name (belongs in `aria-label`) or a description (belongs in a tooltip with `aria-describedby`). ## 3. Genuine tooltips, `title` only — 22 elements - `components/scheduling/QueuedRow.vue` (5) - `components/attachments/HtmlPreviewModal.vue` (3), `PdfPreviewModal.vue` (3) - `components/scheduling/ScheduledStripModal.vue` (3) - `components/cards/MmSourceBreadcrumb.vue` (2) - `CardRow.vue`, `ImageLightbox.vue`, `ReplyComposer.vue`, `SendButton.vue`, `DraftBadge.vue`, `DevUserSwitcher.vue` (1 each) Fix: `nldd-tooltip`. It wraps the child with `display: contents` so layout is untouched, shows on hover *and* focus, suppresses itself on touch, sets `aria-describedby` itself, and takes `placement` and `timing` (`instant` / `default` / `never`). ## Why this is its own issue Split off from #181 deliberately. That one is about typography and design tokens; this changes behaviour - focus, touch, and what a screen reader announces - so it wants its own pass with a keyboard and a screen reader, and a judgement per element on whether the text is essential or decorative.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
robbertbos/waggle#197
No description provided.