Features
- No dependencies or frameworks required
- Works with mouse, touch, and keyboard focus
- Customizable via CSS variables
- Gradient and image backgrounds and borders
- Smart positioning and viewport detection
- Smooth animations with smart skip-delay between adjacent tooltips
- Anchor to the trigger element, the cursor, or where the user first hovered
- Plain text or arbitrary HTML content
- Seamless body + arrow drawn as a single SVG path
- Works in Vue, React, Svelte, and more
Demos
Tooltips in little UI scenes. The first is the default look; the rest combine variables with a little custom CSS. Hover or focus the elements in each scene.
- Unlimited projects i
- Priority support i
- Advanced analytics i
Basic Usage
Simply add the data-easy-tooltip attribute to any element:
Button
Text Element
Hover over username
Icon
<button data-easy-tooltip="Click to save your changes">Save</button> <span data-easy-tooltip="This field is required">username</span> <div data-easy-tooltip="Multi-line tooltips are supported">Info</div>
Custom HTML
Use data-easy-tooltip-src to pull content from another element:
CSS Selector
Delivered in 2-4 working days
From Next Element
- Oats
- Honey
- Sea salt
<button data-easy-tooltip-src="#tip-shipping">Shipping Info</button> <template id="tip-shipping"> <strong>Free shipping</strong> on orders over £50<br> Delivered in 2-4 working days </template> <button class="btn btn-success" data-easy-tooltip-src="next">Ingredients</button> <div style="display: none;"> <ul><li>Oats</li><li>Honey</li><li>Sea salt</li></ul> </div>
Dynamic Tooltips
Tooltips automatically update when the data-easy-tooltip attribute changes. Hover over the elements below to see live updates:
Live Counter
Current Time
<button id="counter" data-easy-tooltip="Count: 0">Hover me</button>
<script>
let count = 0
setInterval(() => {
document.getElementById("counter").dataset.easyTooltip = `Count: ${++count}`
}, 1000)
</script>
Smart Positioning
Tooltips automatically adapt to screen boundaries. Hover over the buttons at the corners of your screen to see smart positioning in action:
Preferred Side
Tooltips show above by default. Use data-easy-tooltip-prefer to pick a side, falling back to the opposite side when there isn't room. Using left or right switches to horizontal mode:
Above (default)
Below
Left
Right
<button data-easy-tooltip="I show above">Hover me</button> <button data-easy-tooltip="I show below" data-easy-tooltip-prefer="below">Hover me</button> <button data-easy-tooltip="I show on the left" data-easy-tooltip-prefer="left">Hover me</button> <button data-easy-tooltip="I show on the right" data-easy-tooltip-prefer="right">Hover me</button>
entry uses whichever edge of the trigger your cursor crossed on the way in, so the tooltip meets you where you arrived. Keyboard focus has no entry point and falls back to above:
Entry
<div data-easy-tooltip="I show on the edge you came in from" data-easy-tooltip-prefer="entry">…</div>
Anchor Modes
By default a tooltip anchors to its trigger element. Use data-easy-tooltip-anchor to change the anchor point: cursor follows the cursor or touch point, pin freezes where the cursor is when the tooltip appears. Both have single axis versions, which take one axis from the cursor and the other from the element. Keyboard focus always falls back to the element.
Cursor
Cursor X
Cursor Y
Pin
Pin X
Pin Y
<div data-easy-tooltip="I follow your cursor" data-easy-tooltip-anchor="cursor">…</div> <div data-easy-tooltip="I snapped to the nearest edge" data-easy-tooltip-anchor="pin">…</div> <div data-easy-tooltip="I follow you sideways" data-easy-tooltip-anchor="cursor-x">…</div> <div data-easy-tooltip="I follow you up and down" data-easy-tooltip-anchor="cursor-y" data-easy-tooltip-prefer="right">…</div>
Events
Tooltips fire easy-tooltip-open, easy-tooltip-close, and easy-tooltip-move on their trigger element. The events bubble, so you can listen on document. move fires when a tooltip flips to another side, and when its anchor point moves. Flips are sent straight away, anchor point changes are limited to one event every 100ms. open fires when the tooltip appears, after any delay, so a hover too brief to show a tooltip fires nothing at all. The buttons below use a .5s delay to make that obvious.
Open and Close
Nothing open
Cursor
Waiting for events
document.addEventListener("easy-tooltip-open", e => {
console.log(e.detail.side, e.detail.point)
})
Custom Colors
Style specific tooltips using data-easy-tooltip-class and CSS variables:
Success
Danger
Info
<button data-easy-tooltip="Saved!" data-easy-tooltip-class="success-tooltip">Save</button>
<button data-easy-tooltip="This cannot be undone!" data-easy-tooltip-class="danger-tooltip">Delete</button>
<div data-easy-tooltip="Get help" data-easy-tooltip-class="info-tooltip">?</div>
<style>
.success-tooltip {
--easy-tooltip-background-color: #f0fdf4;
--easy-tooltip-border-color: #27ae60;
--easy-tooltip-text-color: #27ae60;
}
.danger-tooltip {
--easy-tooltip-background-color: #fef2f2;
--easy-tooltip-border-color: #e74c3c;
--easy-tooltip-text-color: #e74c3c;
}
.info-tooltip {
--easy-tooltip-background-color: #faf5ff;
--easy-tooltip-border-color: #9b59b6;
--easy-tooltip-text-color: #9b59b6;
}
</style>
Backgrounds & Borders
Beyond flat colors, --easy-tooltip-background and --easy-tooltip-border accept any CSS image: gradients or url() images. Both follow the tooltip shape, arrow included. They can also be set per element with the data-easy-tooltip-background and data-easy-tooltip-border attributes.
Gradient Background
Image Background
Gradient Border
Rainbow Border
<button data-easy-tooltip="Gradient background" data-easy-tooltip-class="gradient-tooltip">Hover me</button>
<button data-easy-tooltip="Image background" data-easy-tooltip-background="url('photo.jpg')">Hover me</button>
<button data-easy-tooltip="Gradient border" data-easy-tooltip-border="linear-gradient(135deg, #f0f, #0ff)">Hover me</button>
<style>
.gradient-tooltip {
--easy-tooltip-background: linear-gradient(135deg, #667eea, #764ba2);
--easy-tooltip-text-color: #fff;
}
</style>
Customization Variables
Fine-tune tooltips with CSS variables:
Custom Border
Max Width
Large Arrow
Wide Arrow
Thin Arrow
No Arrow
Rounded Arrow Point
Delay
Longer Animation
Dark Theme
Slide Distance
Far From Element
<style>
:root {
--easy-tooltip-background-color: #fff; /* Background color */
--easy-tooltip-text-color: #000; /* Text color */
--easy-tooltip-border-color: #aaa; /* Border color */
--easy-tooltip-border-size: 1px; /* Border thickness */
--easy-tooltip-background: none; /* Background image/gradient, replaces the background color */
--easy-tooltip-border: none; /* Border image/gradient, replaces the border color */
--easy-tooltip-border-radius: 4px; /* Corner radius of the tooltip */
--easy-tooltip-padding: 8px 12px; /* Inner padding */
--easy-tooltip-max-width: 100%; /* Maximum tooltip width */
--easy-tooltip-distance: 16px; /* Distance from trigger element */
--easy-tooltip-viewport-padding: 16px; /* Minimum distance from screen edges */
--easy-tooltip-arrow-size: 16px; /* Arrow size (height defaults to width / 2; 0 to disable) */
--easy-tooltip-arrow-size: 16px 8px; /* Or specify arrow width and height separately */
--easy-tooltip-arrow-edge-buffer-x: 12px; /* Arrow gap from corner (for above or below tooltips) */
--easy-tooltip-arrow-edge-buffer-y: 6px; /* Arrow gap from corner (for left or right tooltips) */
--easy-tooltip-arrow-radius: 0; /* Border radius of the arrow tip */
--easy-tooltip-animation-length: 0.15s; /* Duration of fade animation */
--easy-tooltip-animation-distance: 4px; /* Distance the tooltip slides in */
--easy-tooltip-delay: 0s; /* Base delay before the tooltip shows; always added */
--easy-tooltip-inactive-delay: 0.15s; /* Extra delay when no tooltip was recently active; drops to 0 once a tooltip is showing */
--easy-tooltip-cooldown: 0.15s; /* How long after the last tooltip closes before the inactive-delay applies again */
}
</style>
Per-Tooltip Adjustments
Reach for data-easy-tooltip-class when you're theming a group of tooltips, and data-easy-tooltip-style when you just need to nudge one. It writes CSS variables straight onto that tooltip's style attribute, so there's no class to name and no stylesheet to touch:
Pill
Swatches
Live Distance
<div data-easy-tooltip="Pill shaped, just for me" data-easy-tooltip-style="--easy-tooltip-border-radius: 999px;">?</div>
<span data-easy-tooltip="Coral" data-easy-tooltip-style="--easy-tooltip-background-color: #ff6f61; --easy-tooltip-text-color: #fff;"></span>
<span data-easy-tooltip="Teal" data-easy-tooltip-style="--easy-tooltip-background-color: #14919b; --easy-tooltip-text-color: #fff;"></span>
<div id="live-distance-area" data-easy-tooltip="Distance: 16px" data-easy-tooltip-style="--easy-tooltip-distance: 16px;">
<input type="range" id="live-distance-slider" min="4" max="60" value="16">
</div>
<script>
const area = document.getElementById("live-distance-area")
const slider = document.getElementById("live-distance-slider")
slider.addEventListener("input", () => {
area.dataset.easyTooltip = `Distance: ${slider.value}px`
area.dataset.easyTooltipStyle = `--easy-tooltip-distance: ${slider.value}px;`
})
</script>