mgifford/accessibility-skills/tooltips

Claude Code and agent skill by mgifford/accessibility-skills

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Load this skill whenever the project contains tooltip components, hover- triggered informational popups, title attribute tooltips, or any content revealed on hover or focus. Under no circumstances create tooltips that are only triggered by hover without keyboard equivalent access. Absolutely always ensure tooltips are dismissible, persistent enough to read, and not the sole source of essential information.

Install

npx vskill@latest install mgifford/accessibility-skills/tooltips

SKILL.md

Tooltips Accessibility Skill

Canonical source: examples/TOOLTIP_ACCESSIBILITY_BEST_PRACTICES.md in mgifford/ACCESSIBILITY.md
This skill is derived from that file. When in doubt, the example is authoritative.

Apply these rules when implementing or reviewing tooltip components. Only load this skill if the project contains tooltips.


Core Mandate

A tooltip is a short, non-interactive description that appears automatically when its trigger receives keyboard focus or pointer hover. An accessible tooltip must be available to keyboard, pointer, touch, magnification, and assistive technology users without hiding essential information or blocking the interface.

Tooltips are often the wrong solution. Persistent visible text, a clear control label, a disclosure, or a dialog is usually easier to discover and use. This guide covers authored tooltips; the HTML title attribute produces a browser-controlled tooltip with different behavior and limitations (see below).

Use the project's skills/bug-reporting/SKILL.md severity/priority framework to grade findings. The severity scale below is a skill-local shorthand, not a universal standard.


Severity Scale (this skill)

LevelMeaning
CriticalTooltip contains essential information with no other access route
SeriousTooltip unreachable by keyboard or AT; interactive content trapped in a tooltip
ModerateTooltip accessible but WCAG 1.4.13 requirements not fully met
MinorBest-practice gap; marginal impact

Choose the Right Pattern First

Calling every small popup a tooltip leads to incorrect semantics and keyboard behavior. Classify the interaction before choosing ARIA:

NeedUse
A control needs a clearer labelImprove its visible label
Short supplementary text should appear automatically on focus or hoverTooltip
Instructions or requirements are needed to complete a taskPersistent visible help text
A user explicitly asks to show or hide short helpButton-controlled disclosure
The popup contains links, buttons, or other controlsNon-modal dialog or another appropriate popup pattern
A decision is required before work can continueModal dialog or alert dialog
An action completed or a process changed stateStatus message, not a tooltip
Text is truncated only because of layoutAllow wrapping, expansion, or another way to read the full text

An authored tooltip: describes an element, appears automatically after focus or hover, contains only non-interactive content, does not receive focus, is associated with its trigger through aria-describedby, remains available while the trigger has focus or the pointer is over the trigger or tooltip, and can be dismissed with Escape.


Critical: Essential Information Must Not Live Only in a Tooltip

A tooltip is supplementary by definition. Put instructions, errors, requirements, and other essential information in persistent visible text. Hiding essential content behind hover/focus only is Critical.

Do not place error messages, legal text, security warnings, or task requirements only in a tooltip. Do not attach essential explanations only to a disabled control — a disabled native form control may not dispatch the pointer/focus events a tooltip expects:

html
<p id="publish-requirement">Add a page title before publishing.</p>
<button type="button" disabled aria-describedby="publish-requirement">
Publish
</button>

Serious: Tooltips Must Appear on Both Hover and Focus

A tooltip that only appears on hover is Serious — keyboard users cannot trigger it. Keep focus on the trigger; a tooltip never receives focus. Do not add the tooltip to the tab sequence or use arrow keys to navigate its text.

js
document.querySelectorAll('[data-tooltip]').forEach((container) => {
const trigger = container.querySelector('[data-tooltip-trigger]');
const tooltip = document.getElementById(trigger.dataset.tooltipId);
if (!tooltip || tooltip.getAttribute('role') !== 'tooltip') return;
let pointerWithin = false;
let triggerFocused = false;
let dismissed = false;
function updateTooltip() {
tooltip.hidden = !(!dismissed && (pointerWithin || triggerFocused));
}
container.addEventListener('pointerenter', () => { pointerWithin = true; dismissed = false; updateTooltip(); });
container.addEventListener('pointerleave', () => { pointerWithin = false; updateTooltip(); });
trigger.addEventListener('focus', () => { triggerFocused = true; dismissed = false; updateTooltip(); });
trigger.addEventListener('blur', () => { triggerFocused = false; updateTooltip(); });
trigger.addEventListener('keydown', (event) => {
if (event.key === 'Escape' && !tooltip.hidden) {
dismissed = true;
updateTooltip();
event.stopPropagation();
}
});
});

Track pointer and focus state separately — closing on pointer-leave when focus still keeps the tooltip active is a common failure. If a positioning library is used, inspect its rendered markup, focus handling, portal location, collision behavior, and cleanup; a library name is not evidence of accessibility.


Serious: ARIA Pattern Must Be Correct

Incorrect ARIA on tooltips is Serious — AT users receive wrong or no supplementary information.

html
<span class="tooltip-container" data-tooltip>
<button type="button" aria-describedby="save-tooltip"
data-tooltip-trigger data-tooltip-id="save-tooltip">
Save
</button>
<span id="save-tooltip" role="tooltip" hidden>
Saves changes to your draft.
</span>
</span>

Rules:

  • Tooltip element must have role="tooltip"; use a native interactive element

for the trigger when the trigger performs an action

  • Trigger must reference tooltip via aria-describedby (not aria-labelledby);

aria-describedby may hold a space-separated list — preserve existing help, error, or instruction references when adding a tooltip

  • Use hidden to conceal; never aria-hidden="true" on an active tooltip
  • Each tooltip must have a unique id, including across repeated components;

render the descriptive node before focus reaches the trigger

  • Do not put role="tooltip" on the trigger itself
  • Tooltips must not be focusable — no tabindex on the tooltip container
  • Do not add aria-live, role="status", or role="alert" to a tooltip
  • Do not use aria-expanded or aria-haspopup for an automatically-displayed

tooltip — those apply to button-controlled disclosures, not tooltips

  • Let the tooltip's text provide its accessible description; avoid an

aria-label that replaces different visible tooltip text

For icon-only triggers, name the control independently — the tooltip is a description, not a replacement for the accessible name:

html
<span class="tooltip-container" data-tooltip>
<button type="button"
aria-label="Delete quarterly report"
aria-describedby="delete-tooltip"
data-tooltip-trigger data-tooltip-id="delete-tooltip">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M5 7h14M9 7V4h6v3m-8 0 1 13h8l1-13"/>
</svg>
</button>
<span id="delete-tooltip" role="tooltip" hidden>
Permanently deletes the report.
</span>
</span>

Avoid repeating exactly the same words as both name and description.


Serious: Button-Controlled Help Is Not a Tooltip

When a user activates a button to show content, use a disclosure pattern instead — do not give the content role="tooltip" and do not add a live region merely because it became visible:

html
<button type="button" id="password-help-button"
aria-expanded="false" aria-controls="password-help">
Password requirements
</button>
<div id="password-help" hidden>
Use at least 12 characters. Include a number and a symbol.
</div>

The expanded state communicates the change; focus remains on the button. If the popup contains interactive controls or must manage focus, use an appropriate dialog or popup pattern.


Moderate: WCAG 1.4.13 — Content on Hover or Focus

RequirementDescriptionSeverity if failing
DismissibleEscape dismisses without moving pointer or focusSerious
HoverableUser can move pointer over tooltip without it disappearingModerate
PersistentStays visible until trigger/tooltip loses hover or focus, is dismissed, or the info is no longer validModerate

Do not invent an auto-close duration — a tooltip that disappears after a fixed timeout does not meet the persistence requirement while its trigger remains active.


Moderate: Touch and Activation

Touch devices do not provide dependable hover. Do not depend on a tooltip for touch access. Use one of:

  • Keep the information visible near the control
  • Include it in the control's accessible name or existing description
  • Provide a separate help button that opens a disclosure (see above)
  • Use a non-modal dialog when the additional content is structured or interactive

Moderate: Do Not Rely on the title Attribute

Browser-controlled title tooltips fall under the WCAG 1.4.13 exception when their presentation is entirely user-agent controlled, but that exception does not make title a dependable interface pattern. Authors cannot ensure consistent keyboard, touch, magnification, timing, text size, or dismissal behavior for title. Do not use title as the only:

  • accessible name for a control
  • source of instructions or validation requirements
  • explanation of an icon
  • way to reveal truncated text
  • access path for touch users

Moderate: Visual Design

  • Normal-size tooltip text needs at least 4.5:1 contrast against its background

(WCAG 1.4.3); large text needs 3:1

  • A boundary, shape, or arrow needs 3:1 contrast against adjacent colors (WCAG

1.4.11) only when that visual information is required to identify the component or state — a decorative arrow is not automatically subject to this

  • Do not rely on color alone to associate a tooltip with its trigger
  • At 400% zoom and narrow viewports: keep the tooltip within the viewport,

allow text to wrap, avoid horizontal scrolling, don't cover the trigger or critical content, and preserve a way to dismiss it

  • Detect viewport edges and reposition; recalculate placement after zoom,

resize, content changes, and text-direction changes; avoid rendering inside an ancestor whose overflow clips the tooltip

  • An icon-button trigger must still meet WCAG 2.2 Target Size (Minimum)
  • Respect prefers-reduced-motion:
css
[role="tooltip"] {
position: absolute;
max-inline-size: min(20rem, calc(100vw - 2rem));
overflow-wrap: anywhere;
}
[role="tooltip"][hidden] { display: none; }
@media (forced-colors: active) {
[role="tooltip"] { color: CanvasText; background: Canvas; border-color: CanvasText; }
}
@media (prefers-reduced-motion: no-preference) {
[role="tooltip"] { transition: opacity 0.15s ease; }
}

Content Requirements

  • Keep content to a short phrase or sentence; describe the trigger, don't

introduce an unrelated message

  • Avoid repeating the trigger's accessible name word for word
  • Do not include headings, lists, links, buttons, fields, or other controls
  • Write in plain language; keep dynamic descriptions stable while the trigger

has focus

  • If content needs structure or several sentences, use persistent help,

aria-details, a disclosure, or a dialog instead

  • Do not make ordinary prose focusable merely to attach a tooltip — extra tab

stops make keyboard navigation harder


When NOT to Use a Tooltip

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 95 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

7-day trend score
0

Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/mgifford/accessibility-skills/tooltips/badge)](https://verified-skill.com/skills/mgifford/accessibility-skills/tooltips)

Something wrong with this skill or its page? Tell us.