Lightweight JS Tooltip Library with Smart Positioning – easy-tooltips

Category: Javascript , Tooltip | September 22, 2026
Authorewanhowell5195
Last UpdateSeptember 22, 2026
LicenseMIT
Tags
Views136 views
Lightweight JS Tooltip Library with Smart Positioning – easy-tooltips

easy-tooltips is a zero-dependency JavaScript tooltip library that attaches custom tooltips to HTML elements through HTML data attributes.

The tooltip can stay with its trigger element, follow the pointer, or pin to a pointer position while the library adjusts placement near viewport edges.

Features

  • Zero-dependency JavaScript and CSS.
  • Data-attribute setup with no initialization call.
  • Viewport-aware placement, side flipping, and edge shifting.
  • Element, cursor, and pinned anchor modes.
  • Mouse, touch, and keyboard focus activation.
  • Plain text and sourced HTML tooltip content.
  • CSS variables, custom classes, inline styles, gradients, and image surfaces.
  • Open, close, and move events.
  • Automatic updates for dynamically changed DOM content.

How to Use It

Browser Setup

Load the stylesheet before the JavaScript file.

<link
  href="https://cdn.jsdelivr.net/npm/easy-tooltips/dist/easy-tooltips.min.css"
  rel="stylesheet"
>
<script src="https://cdn.jsdelivr.net/npm/easy-tooltips/dist/easy-tooltips.min.js"></script>

Install with npm

Install the package from npm and import its stylesheet and JavaScript entry point.

# NPM
npm install easy-tooltips
import "easy-tooltips/styles.css";
import "easy-tooltips";

Basic Usage

Set data-easy-tooltip on a trigger element and put plain text in the attribute value. Use a newline entity when one text tooltip needs multiple lines.

<button data-easy-tooltip="Save your current settings">
  Save
</button>
<span
  tabindex="0"
  data-easy-tooltip="Account status&#10;Updated a few seconds ago"
>
  Status
</span>

Smart Tooltip Positioning

Each tooltip starts on its preferred side. The default is above. You can choose below, left, right, or entry with data-easy-tooltip-prefer. The entry value uses the edge where the pointer entered the trigger and uses above for keyboard focus.

When the preferred side lacks space, easy-tooltips tries the opposite side and shifts the tooltip along the available edge. An inside placement keeps the tooltip within the viewport when neither side has enough room. Placement is recalculated on scroll and resize events, and Visual Viewport dimensions are used when that browser API is available.

<button
  data-easy-tooltip="Opens below when space is available"
  data-easy-tooltip-prefer="below"
>
  Below
</button>
<button
  data-easy-tooltip="Uses the pointer entry edge"
  data-easy-tooltip-prefer="entry"
>
  Entry side
</button>

Cursor and Pin Anchor Modes

data-easy-tooltip-anchor accepts element, cursor, cursor-x, cursor-y, pin, pin-x, and pin-y. The default element mode uses the trigger box. Cursor modes track pointer coordinates. Pin modes freeze the selected pointer coordinate when the tooltip appears.

The full pin mode snaps to the nearest trigger edge. Its placement follows the pointer entry side unless data-easy-tooltip-prefer specifies another side. Keyboard focus uses element anchoring because it has no pointer coordinates.

<button
  data-easy-tooltip="Tracks the pointer"
  data-easy-tooltip-anchor="cursor"
>
  Inspect
</button>
<button
  data-easy-tooltip="Pins to the nearest trigger edge"
  data-easy-tooltip-anchor="pin"
>
  Pin tooltip
</button>
<button
  data-easy-tooltip="Tracks horizontal pointer movement"
  data-easy-tooltip-anchor="cursor-x"
>
  Track X axis
</button>

Keep a Tooltip Open During Pointer Interaction

Pressing a supported control keeps its tooltip visible until pointer release. The default applies to inputs, selects, textareas, buttons, and common button, slider, checkbox, radio, and switch roles.

Set data-easy-tooltip-hold on another trigger to opt in. Set data-easy-tooltip-hold="false" on a supported control to disable this behavior.

<div
  data-easy-tooltip="Stays visible while dragging"
  data-easy-tooltip-hold
>
  Drag handle
</div>
<button
  data-easy-tooltip="Hides after pointer exit"
  data-easy-tooltip-hold="false"
>
  Press
</button>

Custom HTML Content

Use data-easy-tooltip-src when a tooltip needs formatted HTML. Its value can reference an element by ID or CSS selector, or use next and prev for adjacent content.

<button data-easy-tooltip-src="#shipping-details">
  Shipping details
</button>
<template id="shipping-details">
  <strong>Free shipping</strong><br>
  Orders usually arrive in 2 to 4 business days.
</template>

The adjacent-source forms hide the matching sibling automatically.

<button data-easy-tooltip-src="next">
  View ingredients
</button>
<div>
  <ul>
    <li>Oats</li>
    <li>Honey</li>
    <li>Sea salt</li>
  </ul>
</div>
<div>
  <strong>Delete warning</strong><br>
  This action removes the saved item.
</div>
<button data-easy-tooltip-src="prev">
  Delete
</button>

Custom Classes and Per-Tooltip Styles

Use data-easy-tooltip-class for reusable visual variants. The attribute accepts one or more class names.

<button
  data-easy-tooltip="Settings saved"
  data-easy-tooltip-class="success-tooltip"
>
  Save
</button>
<button
  data-easy-tooltip="This action cannot be undone"
  data-easy-tooltip-class="danger-tooltip bold-tooltip"
>
  Delete
</button>
.success-tooltip {
  --easy-tooltip-background-color: #f0fdf4;
  --easy-tooltip-border-color: #27ae60;
  --easy-tooltip-text-color: #166534;
}
.danger-tooltip {
  --easy-tooltip-background-color: #fef2f2;
  --easy-tooltip-border-color: #e74c3c;
  --easy-tooltip-text-color: #991b1b;
}
.bold-tooltip {
  font-weight: 700;
}

For a one-off visual change, data-easy-tooltip-style applies inline CSS to the generated tooltip.

<span
  tabindex="0"
  data-easy-tooltip="Pill-shaped tooltip"
  data-easy-tooltip-style="--easy-tooltip-border-radius: 999px; --easy-tooltip-padding: 8px 16px;"
>
  Account
</span>

Gradient and Image Backgrounds

--easy-tooltip-background and --easy-tooltip-border accept CSS image values such as gradients and url() images. The related data attributes set these values on individual tooltips.

.brand-tooltip {
  --easy-tooltip-background: linear-gradient(135deg, #667eea, #764ba2);
  --easy-tooltip-border: linear-gradient(135deg, #f0f, #0ff);
  --easy-tooltip-border-size: 2px;
  --easy-tooltip-text-color: #fff;
}
<button
  data-easy-tooltip="Gradient border"
  data-easy-tooltip-border="linear-gradient(135deg, #f0f, #0ff)"
>
  Details
</button>
<button
  data-easy-tooltip="Image background"
  data-easy-tooltip-background="url('tooltip-texture.jpg')"
>
  Preview
</button>

All HTML Data Attribute

AttributeDescription
data-easy-tooltipSets plain text tooltip content. Newlines are supported.
data-easy-tooltip-srcCopies HTML content from an element ID, CSS selector, next, or prev.
data-easy-tooltip-classApplies one or more class names to the generated tooltip.
data-easy-tooltip-styleApplies inline CSS to one generated tooltip.
data-easy-tooltip-preferSets above, below, left, right, or entry as the preferred placement.
data-easy-tooltip-anchorSets element, cursor, single-axis cursor, pin, or single-axis pin anchoring.
data-easy-tooltip-holdKeeps the tooltip open during a pointer press, or disables automatic hold behavior when set to false.
data-easy-tooltip-backgroundSets a CSS image or gradient background for one tooltip.
data-easy-tooltip-borderSets a CSS image or gradient border for one tooltip.

CSS Variables

Override these custom properties on :root for a global theme or on a tooltip class for a local variant.

Appearance

CSS VariableDescription
--easy-tooltip-background-color
Default: #fff
Base tooltip fill color.
--easy-tooltip-text-color
Default: #000
Tooltip text color.
--easy-tooltip-border-color
Default: #aaa
Base border color.
--easy-tooltip-border-size
Default: 1px
Border thickness.
--easy-tooltip-border-radius
Default: 4px
Tooltip corner radius.
--easy-tooltip-padding
Default: 8px 12px
Inner spacing around tooltip content.
--easy-tooltip-max-width
Default: 100%
Maximum tooltip width.
--easy-tooltip-background
Default: none
CSS image or gradient used for the tooltip body and arrow.
--easy-tooltip-border
Default: none
CSS image or gradient used for the tooltip border.

Positioning

CSS VariableDescription
--easy-tooltip-distance
Default: 16px
Gap between the anchor and tooltip.
--easy-tooltip-viewport-padding
Default: 16px
Minimum spacing from viewport edges.
--easy-tooltip-arrow-size
Default: 16px
Arrow width. One value uses half that value for height. Two values set width and height separately. Set the value to 0 to hide the arrow.
--easy-tooltip-arrow-edge-buffer-x
Default: 12px
Horizontal arrow spacing from rounded corners for above and below tooltips.
--easy-tooltip-arrow-edge-buffer-y
Default: 6px
Vertical arrow spacing from rounded corners for left and right tooltips.
--easy-tooltip-arrow-radius
Default: 0
Radius applied to the SVG arrow tip.

Animation and Delay

CSS VariableDescription
--easy-tooltip-animation-length
Default: 0.15s
Fade and movement transition duration.
--easy-tooltip-animation-distance
Default: 4px
Distance used for the entrance movement.
--easy-tooltip-delay
Default: 0s
Base delay applied before each tooltip opens.
--easy-tooltip-inactive-delay
Default: 0.15s
Extra delay used when no tooltip was recently active.
--easy-tooltip-cooldown
Default: 0.15s
Time after the last tooltip closes before the inactive delay applies again.

Customize the Global Theme

This theme changes the main colors, width, spacing, arrow geometry, and timing values in one place.

:root {
  --easy-tooltip-background-color: #111827;
  --easy-tooltip-text-color: #f9fafb;
  --easy-tooltip-border-color: #374151;
  --easy-tooltip-border-size: 1px;
  --easy-tooltip-border-radius: 6px;
  --easy-tooltip-padding: 8px 12px;
  --easy-tooltip-max-width: 320px;
  --easy-tooltip-distance: 12px;
  --easy-tooltip-viewport-padding: 12px;
  --easy-tooltip-arrow-size: 14px 7px;
  --easy-tooltip-arrow-radius: 2px;
  --easy-tooltip-animation-length: 0.15s;
  --easy-tooltip-animation-distance: 4px;
  --easy-tooltip-delay: 0s;
  --easy-tooltip-inactive-delay: 0.2s;
  --easy-tooltip-cooldown: 0.15s;
}

Tooltip Events

Listen on a trigger element or on document when application code needs to react to tooltip visibility or placement changes. The custom events bubble from the trigger.

// Fires after the tooltip actually appears.
document.addEventListener("easy-tooltip-open", (event) => {
  console.log(event.detail.side, event.detail.point);
});
// Fires when the tooltip starts hiding.
document.addEventListener("easy-tooltip-close", (event) => {
  console.log(event.detail.trigger);
});
// Fires after the tooltip changes side or anchor position.
document.addEventListener("easy-tooltip-move", (event) => {
  console.log(event.detail.previous, event.detail.rect);
});

Event Detail

PropertyDescription
triggerThe element associated with the tooltip.
tooltipThe generated tooltip element.
textThe tooltip text content.
sideThe current above, below, left, or right placement.
insidetrue when the tooltip uses the inside fallback placement.
anchorThe active anchor mode.
anchorRectThe viewport-coordinate box used as the anchor.
pointThe viewport-coordinate point targeted by the tooltip arrow.
rectThe current tooltip box in viewport coordinates.
previousPrevious placement data on easy-tooltip-move.

Alternatives & Related Resources

FAQs

Q: Why does a tooltip on a span or div not open from the keyboard?
A: Plain spans and divs are not focusable by default. Add tabindex="0" when the trigger should receive keyboard focus.

Q: How do I place HTML inside a tooltip?
A: Put the formatted content in a template or nearby element and reference it with data-easy-tooltip-src. The value accepts an element ID, CSS selector, next, or prev.

Q: What happens when a tooltip does not fit on its preferred side?
A: The positioning logic tries the opposite side and shifts the tooltip along the available edge. An inside placement is used when neither side has enough room.

Q: Can application code react when a tooltip moves?
A: Yes. Listen for easy-tooltip-move on the trigger or a parent such as document. Its event detail includes current placement data and the previous placement.

Changelog

v3.5.4 (09/22/2026)

  • Bugfixes

v3.5.2 (08/31/2026)

  • Tooltips now hold their opening spot while their trigger scrolls, only following it along the axis the arrow points and clamping to the trigger’s edge once it reaches them. Before they tracked the trigger on both axes, which made them jitter in scrollable lists.
  • Bugfixes.

v3.5.1 (08/23/2026)

  • Added easy-tooltip-open, easy-tooltip-close, and easy-tooltip-move events.
  • Expanded data-attribute controls for anchor and interaction behavior.
  • Updated pin anchoring to snap to the nearest trigger edge when appropriate.
  • Updated pin timing to capture the anchor point when the tooltip appears.
  • Fixed positioning and interaction bugs.

v3.3.0 (08/20/2026)

  • Added data-easy-tooltip-style for per-tooltip inline styling.

v3.2.0 (08/20/2026)

  • Added data-easy-tooltip-src="prev".
  • Added Popover API top-layer rendering where supported.

v3.1.0 (07/21/2026)

  • Added image and gradient backgrounds through --easy-tooltip-background.
  • Added image and gradient borders through --easy-tooltip-border.

v3.0.0 (05/24/2026)

  • Added element, cursor, and pin anchor modes.
  • Added skip-delay timing for movement between adjacent tooltips.
  • Changed the tooltip body and arrow to a single SVG path.
  • Added newest-on-top stacking for simultaneous tooltips.
  • Changed the default arrow size to 16px.
  • Changed --easy-tooltip-delay to 0s and moved the initial wait to --easy-tooltip-inactive-delay.

v2.0.0 (05/22/2026)

  • Expanded and renamed the tooltip data attributes.
  • Fixed multiple tooltip behavior issues.

v1.5.0 (03/16/2026)

  • Added MutationObserver support for dynamically changed tooltip triggers.

v1.4.3 (01/26/2026)

  • Added newline support and configurable tooltip delays.
  • Updated custom HTML handling to use source elements and reject raw HTML strings.

You Might Be Interested In:


Leave a Reply