# How to Optimize Tooltip Performance with a Delayed First Show

> Optimize tooltip performance with a delayed first show. Learn how to use CSS transitions and data attributes to eliminate latency for a smoother user experience.

- Repository: [Emil Kowalski/skills](https://github.com/emilkowalski/skills)
- Tags: performance
- Published: 2026-07-29

---

**Use a CSS `transition-delay` for the first tooltip appearance, then dynamically set `transition-duration: 0ms` via a `data-instant` attribute for all subsequent tooltips to eliminate perceived latency.**

The **emilkowalski/skills** repository codifies a battle-tested pattern for toolbar interactions that prevents accidental activations while maintaining snappy perceived performance. This approach applies a brief delay on initial hover to avoid visual noise, then instantly displays neighboring tooltips once the user has engaged with the interface.

## Why Delay the First Tooltip Show?

Dense toolbars suffer from **accidental activation** when users sweep their cursor across the screen. A short delay—typically implemented via `transition-delay` or a JavaScript timeout—acts as a safety buffer, ensuring tooltips appear only when the user actually pauses on an element.

According to the design engineering guidelines in [`skills/emil-design-eng/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/emil-design-eng/SKILL.md), the first hover should require intentional intent, while subsequent interactions within the same toolbar should feel immediate (lines 47-48).

## The Core Pattern: Delayed First Show, Instant Subsequent Displays

The pattern relies on three layers: CSS transitions for the animation, HTML data attributes for state tracking, and minimal JavaScript to toggle between "animated" and "instant" modes.

### CSS Implementation

Define the base tooltip with a standard transition using only GPU-accelerated properties, as mandated by the repository's animation standards ([`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md), lines 110-118).

```css
/* Base tooltip – delayed first show */
.tooltip {
  transition: transform 125ms ease-out, opacity 125ms ease-out;
  transform-origin: var(--transform-origin);
}

/* Initial hidden state */
.tooltip[data-starting-style],
.tooltip[data-ending-style] {
  opacity: 0;
  transform: scale(0.97);
}

/* Instant tooltip – subsequent shows */
.tooltip[data-instant] {
  transition-duration: 0ms;
}

```

The `data-instant` attribute overrides the transition duration, eliminating the 125ms fade-in for any tooltip flagged after the first display.

### HTML Structure

Mark each tooltip with `data-starting-style` to handle the entry animation, leaving room for the JavaScript to inject `data-instant` dynamically.

```html
<button class="btn" data-tooltip-id="save">Save</button>
<div id="tooltip-save" class="tooltip" data-starting-style>Save changes</div>

<button class="btn" data-tooltip-id="delete">Delete</button>
<div id="tooltip-delete" class="tooltip" data-starting-style>Delete item</div>

```

### JavaScript State Management

Track whether the first tooltip has been shown using a simple boolean flag. Once triggered, set `data-instant` on all tooltips in the group to skip future animations.

```javascript
const tooltipGroup = document.querySelectorAll('.tooltip');
let firstShown = false;

tooltipGroup.forEach(tooltip => {
  tooltip.addEventListener('mouseenter', () => {
    tooltip.classList.add('visible');
    
    if (!firstShown) {
      firstShown = true;
    } else {
      tooltip.setAttribute('data-instant', '');
    }
  });

  tooltip.addEventListener('mouseleave', () => {
    tooltip.classList.remove('visible');
  });
});

```

This logic ensures the delay applies only once per toolbar session, creating the perception of a faster interface without sacrificing the initial safety buffer.

## Performance Benefits of Skipping Subsequent Animations

Removing the transition delay after the first show delivers measurable improvements in **perceived performance** and **rendering efficiency**.

**Perceived Speed**: A 125ms fade-in feels slower than an immediate pop-in, even though the computational cost is minimal. As noted in the repository standards ([`STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/STANDARDS.md), line 49), instant tooltips after the first interaction make toolbars feel significantly more responsive.

**GPU Optimization**: By animating only `transform` and `opacity`, the browser stays on the compositor thread. Setting `transition-duration: 0ms` avoids unnecessary style recalculations and paint work for subsequent tooltips.

**Reduced Layout Thrashing**: Because `data-instant` modifies only the transition duration—a property that does not trigger layout—the browser skips expensive reflow cycles when rapidly hovering over multiple buttons.

## Complete Working Example

Combine the CSS, HTML, and JavaScript patterns into a self-contained toolbar implementation.

```html
<style>
  .tooltip {
    position: absolute;
    pointer-events: none;
    opacity: 0;
    transform: scale(0.97);
    transition: transform 125ms ease-out, opacity 125ms ease-out;
    background: #1a1a1a;
    color: white;
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 12px;
  }

  .tooltip.visible {
    opacity: 1;
    transform: scale(1);
  }

  .tooltip[data-instant] {
    transition-duration: 0ms;
  }

  .toolbar {
    display: flex;
    gap: 8px;
  }
</style>

<div class="toolbar">
  <button class="btn" data-tooltip="tip-bold">Bold</button>
  <button class="btn" data-tooltip="tip-italic">Italic</button>
  <button class="btn" data-tooltip="tip-link">Link</button>
</div>

<div id="tip-bold" class="tooltip">Bold (Ctrl+B)</div>
<div id="tip-italic" class="tooltip">Italic (Ctrl+I)</div>
<div id="tip-link" class="tooltip">Insert link</div>

<script>
  const btns = document.querySelectorAll('.toolbar .btn');
  let firstTooltipShown = false;

  btns.forEach(btn => {
    const tip = document.getElementById(btn.dataset.tooltip);
    
    btn.addEventListener('mouseenter', () => {
      tip.classList.add('visible');
      if (firstTooltipShown) {
        tip.setAttribute('data-instant', '');
      }
      firstTooltipShown = true;
    });

    btn.addEventListener('mouseleave', () => {
      tip.classList.remove('visible');
    });
  });
</script>

```

This implementation follows the **Emil‑Design‑Eng** skill guidelines exactly, using `data-starting-style` for entry states and `data-instant` for subsequent optimizations as defined in [`skills/emil-design-eng/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/emil-design-eng/SKILL.md) (lines 52-66).

## Summary

- **Delay the first show** using `transition-delay` or JavaScript timeouts to prevent accidental activations when users sweep their cursor across toolbars.
- **Set `data-instant`** after the first tooltip appears to change `transition-duration` to `0ms` for all subsequent tooltips in the group.
- **Animate only `transform` and `opacity`** to remain on the GPU compositor thread and avoid layout or paint recalculations.
- **Reference source files** [`skills/emil-design-eng/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/emil-design-eng/SKILL.md) and [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md) for canonical implementation patterns and performance budgets.

## Frequently Asked Questions

### What is the optimal delay duration for the first tooltip show?

The repository does not mandate a specific millisecond count, but typical implementations use between **100ms and 150ms** for the initial delay. This duration is long enough to distinguish intentional hovers from cursor sweeps, yet short enough to avoid feeling unresponsive. The [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md) file emphasizes keeping all animations under 300ms total (line 49), so ensure your delay plus fade-in duration stays below this threshold.

### Why not just disable animations entirely for all tooltips?

Completely removing animations reduces perceived quality and can cause **cognitive disorientation** when UI elements pop in without transition. The delayed-first-show pattern specifically protects against accidental triggers during cursor movement while preserving the polished feel of an animated entry. Once the user has engaged with the toolbar, instant subsequent displays prioritize speed over aesthetics.

### How does the `data-instant` attribute improve GPU performance?

When a browser encounters `transition-duration: 0ms` via the `data-instant` selector, it skips the interpolation calculations and composite layers required for animation. Because the CSS uses only `transform` and `opacity`—properties that do not trigger layout or paint—the browser avoids expensive CPU cycles spent recalculating geometry or rasterizing pixels when rapidly hovering between adjacent buttons.

### Can this pattern work without JavaScript?

Pure CSS implementations can approximate this behavior using the `:hover` pseudo-class on a parent container, but they cannot reliably track "first show" state across separate tooltip elements. The JavaScript approach in [`skills/emil-design-eng/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/emil-design-eng/SKILL.md) (lines 52-66) requires minimal overhead—typically under 50 lines—and provides precise control over when to inject the `data-instant` flag, making it the recommended method for production toolbars.