---
title: "JavaScript Tooltip"
description: "The LemonadeJS Tooltip block for JavaScript: Hover tooltips. Contract-verified, framework-agnostic, zero dependencies, with a live example."
source: https://lemonadejs.com/docs/plugins/tooltip/
---

<link rel="stylesheet" href="/v6/tooltip.css">

# JavaScript Tooltip

`@lemonadejs/tooltip` · ✓ 13 contract checks · framework-agnostic · zero dependencies

`<Tooltip />` — a floating label for any element.

Wraps its children and shows a small dark pill on hover/focus of the
wrapper; hides on leave/blur/Escape. The popper is HOVERABLE (WCAG
1.4.13): leaving the wrapper starts a short grace timer instead of
hiding, so the pointer can travel across the gap onto the popper —
re-entering the subtree (trigger or popper) cancels the hide. While
visible, the trigger children are wired to the popper through
aria-describedby. Self-contained on purpose: a tooltip is too small to
compose `<Modal />` — no chrome, no drag, no focus management, just one
branch and four coordinates.

  <${Tooltip} title="Save your work" position="top">
      `<button>`Save`</button>`
  </${Tooltip}>

Placement: the popper is position:fixed, its coordinates computed from
the wrapper's getBoundingClientRect at show time. When the requested
side would leave the viewport the popper FLIPS to the opposite side
(the modal's autoadjust idea, specialized to four sides) — the
effective side is published as data-position so the arrow follows.

## Example

<!--example-->

```js
import { html } from 'lemonadejs';
import Tooltip from '@lemonadejs/tooltip';

const App = (props, { state }) => {
    const saved = state('');

    return html`<div style="display:flex;gap:12px;align-items:center;padding:36px 0">
        <${Tooltip} title="Save the draft (Ctrl+S)" position="top">
            <button onclick="${() => (saved.value = 'Draft saved at ' + new Date().toLocaleTimeString())}">Save</button>
        </${Tooltip}>
        <${Tooltip} title="Share a read-only link" position="bottom">
            <button>Share</button>
        </${Tooltip}>
        <${Tooltip} title="Deleting is permanent" position="right">
            <button>Delete</button>
        </${Tooltip}>
        <span>${saved}</span>
    </div>`;
};
```

## Installation

```bash
npm install @lemonadejs/tooltip
```

```js
import Tooltip from '@lemonadejs/tooltip';
import '@lemonadejs/tooltip/style.css';
```

Three deployment forms, one component:

```js
html`<${Tooltip} />`                       // by value (no registration)
setComponents({ Tooltip });               // then <Tooltip /> by name anywhere
createWebComponent(Tooltip);              // <lm-tooltip> in plain HTML/any framework
```

## Props

Every declared prop arrives as a **live state** — pass a value for a snapshot or a
state for a two-way live wire. Attribute strings are coerced to the declared type.

| Prop | Type | Default | Description |
|---|---|---|---|
| `title` | string | `''` | the tooltip text (live) |
| `position` | string | `''` | '' = top | bottom | left | right |
| `delay` | number | `100` | ms before showing |
| `arrow` | boolean | `true` | small arrow pointing at the wrapper |
| `disabled` | boolean | `false` | never shows |

## Events

All event names are lowercase (the platform convention — LJS-305 warns otherwise).

- `onopen` — fires when the popper appears
- `onclose` — fires when a visible popper hides

## Styling

All classes follow the `lm-tooltip-*` convention; visual variants are `data-*`
attributes on the root. Override freely — there is no styling engine to fight.

## Contract

The machine-readable schema ships with the package:

```js
import contract from '@lemonadejs/tooltip/contract.json';
```

`verify.json` carries the conformance proof produced by `verify(Tooltip)`.

Looking for the v5 plugin? See the [archived v5 documentation](/docs/v5/plugins/).