Kevin DukkonProduct designer
Reads

Timing tooltips

Delay the first, skip the rest.

How long should a tooltip wait? Most products either show it on contact or make you wait a second or longer. For most interfaces, a better answer is to delay the first tooltip by 400ms, then open the next ones at once. Below is how that plays out, from the moment the pointer lands to the moment it leaves, and when not to wait at all.

Active
Fix the white flash on reloadnowweb-appfix/theme-flash
Debounce the search field2mweb-appfix/search
Stack toasts from the bottom14mdesign-systemfeat/toasts
Checks running0:143 of 5 checks passedReview requested2:08Waiting for your approvalReady to merge+48 −123 files changed
A sidebar of pull requests with status dots that explain themselves in tooltips, opening at once, after 400ms and then at once, or after a full second every time.

Delay the first tooltip

On its way across the screen, a pointer passes over plenty of controls it has no interest in. Without a delay, each of them flashes a tooltip, and the interface feels nervous. The delay is how a tooltip tells passing from pausing.

Anywhere from 300 to 500ms works. Nielsen Norman Group recommends that range for content revealed on hover, and Windows tooltips wait 500ms by default. 400ms is a good place to start. The button itself reacts at once, so the pause feels intended, not broken.

The button reacts at once. The tooltip opens once the pointer has rested for 400ms.

Skip the delay for the next ones

Once the first tooltip is open, the person is reading the controls, not passing them. Making them wait at every neighbour is what makes a toolbar feel slow, so the next tooltips open at once.

Keep that going for a moment after a tooltip closes. If the pointer reaches another button within 300ms, it still skips the wait. Radix, Base UI and React Aria all work this way; only the length of that window differs.

First one waits
The next one: at once
The first tooltip waits 400ms. Moving on to the next button, its tooltip opens at once.

Don't wait when pointing is the task

The wait protects people from controls they're only passing. When the pointer is there on purpose, there's nothing to protect. Charts are the clearest case: every point should answer right away. The same goes for the value on a slider while it's dragged and the preview while scrubbing a video.

3k2k1k0Oct 1Oct 8Oct 15Oct 22Oct 29
Tue, Oct 27Visits1,841
On a chart, moving the pointer is how people read it, so every point answers at once.

A quick test: would someone point here only to see the tooltip? Then don't make them wait.

Close it fast, but let it be reached

When the pointer leaves, the tooltip should go. Nielsen Norman Group suggests up to half a second before hiding content shown on hover; for a one-line tooltip, about 100ms is enough. It still feels immediate, and it gives the pointer time to cross onto the tooltip, which WCAG requires: content shown on hover has to stay while the pointer is on it.

A click closes it too, and it stays closed until the pointer leaves the button. Escape closes it without moving the pointer.

Keep it short

A tooltip that opens and closes this quickly has to be read at a glance:

  • One line, a few words. If it needs a heading or a link, it's a popover.
  • It adds to the label, it doesn't repeat it. Text buttons rarely need one.
  • The keyboard shortcut sits next to the name.
  • It sits 8px from its trigger and never covers what it explains.
  • Nothing important lives only in a tooltip. Touch screens can't hover.

Make it work without a mouse

The wait is for pointers. Keyboard focus is a deliberate step, so the tooltip opens at once:

InputTooltip
Pointer restsOpens after 400ms
Pointer moves onOpens at once
Pointer leavesCloses within 100ms
Pointer on a chartOpens at once
Keyboard focusOpens at once
EscapeCloses, focus stays where it is
Click or tapCloses until the pointer leaves

Touch has no hover at all, which is the best reason to keep tooltips optional. Every icon button still needs an accessible name, whether a tooltip shows or not.

How design systems time their tooltips

They all shorten or skip the wait for the next tooltip. They disagree on the first one.

SystemFirstNext
Radix UI700ms0ms
Base UI600ms0ms
MUI100ms0ms
Windows500ms100ms
This guide400ms0ms

In code

In Radix, that's two props on the provider: delayDuration={400} and skipDelayDuration={300}. Without a library, it's one timer and one timestamp:

const OPEN_DELAY = 400 // the first tooltip waits
const SKIP = 300 // the next ones don't, for this long

let timer
let openTip = null
let closedAt = -Infinity

function onEnter(tip) {
  clearTimeout(timer)
  const warm = openTip || performance.now() - closedAt < SKIP
  if (warm) return show(tip)
  timer = setTimeout(() => show(tip), OPEN_DELAY)
}

function onLeave() {
  clearTimeout(timer)
  if (!openTip) return
  timer = setTimeout(() => {
    hide()
    closedAt = performance.now()
  }, 100)
}

function onTooltipEnter() {
  clearTimeout(timer) // the pointer made it across, keep it open
}

function onFocus(tip) {
  clearTimeout(timer)
  show(tip) // keyboard focus never waits
}