Dit is één mogelijke implementatie, er zijn meerdere implementaties mogelijk.
Tooltips zijn een kleine informatievensters die verschijnen bij hover of focus van een element. Ze geven extra informatie zonder je interface vol te proppen.
Gebruik een tooltip:
- Voor korte hulpteksten bij formuliervelden
- Om icoontjes uit te leggen
- Bij afkortingen of technische termen
Een goede tooltip:
- Blijft staan als je eroverheen hovert
- Verdwijnt niet vanzelf
- Kan worden verborgen met Escape
Technische opbouw
- Koppel de beschrijving met
aria-describedby
, gebruik hetid
van de tooltip - Geef de container van de tooltip de rol
tooltip
(role="tooltip"
)
Voorbeeld tooltip
HTML
<!-- Tooltip code -->
<div class="tooltip-container">
<button id="help-button" aria-describedby="help-tooltip">
Help
</button>
<div class="tooltip position-top" role="tooltip" id="help-tooltip" aria-hidden="true">
Extra informatie
</div>
</div>
CSS
/* Tooltip stijlen */
.tooltip-container {
position: relative;
display: inline-block;
}
/* Base tooltip styling */
.tooltip {
position: absolute;
background: black;
color: white;
padding: 8px 12px;
border-radius: 4px;
font-size: 0.8rem;
white-space: nowrap;
z-index: 1000;
opacity: 0;
visibility: hidden;
transition: opacity 0.2s ease-in-out;
pointer-events: none;
}
/* Tooltip positioning - boven (voorkeur) */
.tooltip.position-top {
bottom: 100%;
left: 50%;
transform: translateX(-50%);
margin-bottom: 5px;
}
.tooltip.position-top::after {
content: '';
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
border: 5px solid transparent;
border-top-color: black;
}
/* Tooltip positioning - rechts (fallback) */
.tooltip.position-right {
top: 50%;
left: 100%;
transform: translateY(-50%);
margin-left: 5px;
}
.tooltip.position-right::after {
content: '';
position: absolute;
top: 50%;
right: 100%;
transform: translateY(-50%);
border: 5px solid transparent;
border-right-color: black;
}
/* Zichtbare tooltip */
.tooltip.show {
opacity: 1;
visibility: visible;
pointer-events: auto;
}
/* Voor grotere tooltips */
.tooltip.large {
white-space: normal;
max-width: 250px;
width: max-content;
}
JavaScript
// Tooltip functionaliteit
class Tooltip {
constructor() {
this.tooltips = document.querySelectorAll('.tooltip-container');
this.isTouch = 'ontouchstart' in window;
this.activeTooltip = null;
if (this.tooltips.length > 0) {
this.init();
}
}
init() {
// Initialiseer alle tooltip containers
this.tooltips.forEach(container => {
const button = container.querySelector('button');
const tooltip = container.querySelector('.tooltip');
if (button && tooltip) {
this.setupTooltip(button, tooltip);
}
});
// Global escape key listener
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && this.activeTooltip) {
this.hide(this.activeTooltip);
this.activeTooltip.button.focus();
}
});
// Close tooltip on outside click (touch devices)
if (this.isTouch) {
document.addEventListener('click', (e) => {
if (this.activeTooltip && !this.activeTooltip.container.contains(e.target)) {
this.hide(this.activeTooltip);
}
});
}
}
setupTooltip(button, tooltip) {
const container = button.closest('.tooltip-container');
const tooltipData = { button, tooltip, container, showTimeout: null, hideTimeout: null };
// ARIA setup
button.setAttribute('aria-describedby', tooltip.id);
if (!this.isTouch) {
// Mouse events voor desktop
button.addEventListener('mouseenter', () => this.show(tooltipData));
button.addEventListener('mouseleave', () => this.hide(tooltipData));
// Prevent hiding when hovering over tooltip
tooltip.addEventListener('mouseenter', () => clearTimeout(tooltipData.hideTimeout));
tooltip.addEventListener('mouseleave', () => this.hide(tooltipData));
}
// Keyboard events
button.addEventListener('focus', () => this.show(tooltipData));
button.addEventListener('blur', () => this.hide(tooltipData));
// Touch events
if (this.isTouch) {
button.addEventListener('click', (e) => {
e.preventDefault();
if (this.activeTooltip === tooltipData) {
this.hide(tooltipData);
} else {
if (this.activeTooltip) {
this.hide(this.activeTooltip);
}
this.show(tooltipData, 0);
}
});
}
}
checkPosition(tooltipData) {
const { button, tooltip } = tooltipData;
const buttonRect = button.getBoundingClientRect();
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
// Bereken beschikbare ruimte
const spaceAbove = buttonRect.top;
const spaceRight = viewportWidth - buttonRect.right;
// Geschatte tooltip dimensies (als niet zichtbaar)
let tooltipWidth = tooltip.offsetWidth || 200;
let tooltipHeight = tooltip.offsetHeight || 40;
// Als tooltip zichtbaar is, gebruik werkelijke dimensies
if (tooltip.classList.contains('show')) {
const tooltipRect = tooltip.getBoundingClientRect();
tooltipWidth = tooltipRect.width;
tooltipHeight = tooltipRect.height;
}
// Check beschikbare ruimte (met margin)
const hasSpaceAbove = spaceAbove >= (tooltipHeight + 10);
const hasSpaceRight = spaceRight >= (tooltipWidth + 10);
// Verwijder bestaande position classes
tooltip.classList.remove('position-top', 'position-right');
// Kies positie: eerst boven proberen, dan rechts
if (hasSpaceAbove) {
tooltip.classList.add('position-top');
} else if (hasSpaceRight) {
tooltip.classList.add('position-right');
} else {
// Fallback: boven (ook al past het niet perfect)
tooltip.classList.add('position-top');
}
}
show(tooltipData, delay = 500) {
clearTimeout(tooltipData.hideTimeout);
// Hide any other active tooltip
if (this.activeTooltip && this.activeTooltip !== tooltipData) {
this.hide(this.activeTooltip);
}
tooltipData.showTimeout = setTimeout(() => {
// Check en stel positie in voordat we tonen
this.checkPosition(tooltipData);
tooltipData.tooltip.classList.add('show');
tooltipData.tooltip.setAttribute('aria-hidden', 'false');
this.activeTooltip = tooltipData;
// Hercheck positie na rendering voor betere precisie
setTimeout(() => this.checkPosition(tooltipData), 10);
}, delay);
}
hide(tooltipData) {
clearTimeout(tooltipData.showTimeout);
tooltipData.hideTimeout = setTimeout(() => {
tooltipData.tooltip.classList.remove('show');
tooltipData.tooltip.setAttribute('aria-hidden', 'true');
if (this.activeTooltip === tooltipData) {
this.activeTooltip = null;
}
}, 100);
}
}
// Initialiseer tooltip systeem
new Tooltip();
Toetsenbord
- Escape:
- Bij een uitgevouwen tooltip: sluit de tooltip
Checklist
Component
- (4.1.2) De tooltip container moet de rol
tooltip
hebben (role="tooltip"
) - (1.3.1) Het element met tooltip moet
aria-describedby
hebben met hetid
van de bijbehorende tooltip
Bronnen
- Tooltip Pattern | APG | WAI | W3C (Engelstalig)
- Tooltips & Toggletips (Engelstalig)
- Building a fully-accessible help tooltip (Engelstalig)