https://github.com/untemps/svelte-use-tooltip
Svelte action to display a tooltip
https://github.com/untemps/svelte-use-tooltip
action javascript svelte svelte-action tooltip
Last synced: about 2 months ago
JSON representation
Svelte action to display a tooltip
- Host: GitHub
- URL: https://github.com/untemps/svelte-use-tooltip
- Owner: untemps
- License: mit
- Created: 2022-01-15T13:53:41.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2026-04-25T15:18:17.000Z (2 months ago)
- Last Synced: 2026-04-25T15:21:13.872Z (2 months ago)
- Topics: action, javascript, svelte, svelte-action, tooltip
- Language: TypeScript
- Homepage: https://svelte-use-tooltip.vercel.app
- Size: 1.01 MB
- Stars: 61
- Watchers: 1
- Forks: 0
- Open Issues: 15
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
Svelte action to display a tooltip
[](https://www.npmjs.com/package/@untemps/svelte-use-tooltip)
[](https://github.com/untemps/svelte-use-tooltip/actions)
[](https://codecov.io/gh/untemps/svelte-use-tooltip)
## Demo
## Installation
```bash
npm i @untemps/svelte-use-tooltip
```
## Usage
### Basic usage
```svelte
import { useTooltip } from '@untemps/svelte-use-tooltip';
const _onTooltipClick = (arg: string, event: Event) => {
console.log(arg, event);
};
Hover me
Hi! I'm a fancy tooltip!
.target {
width: 10rem;
height: 3rem;
background-color: white;
color: black;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.5);
}
.target:hover {
cursor: pointer;
background-color: black;
color: white;
}
.tooltip__content {
background-color: yellow;
color: black;
}
:global(.tooltip) {
position: absolute;
z-index: 9999;
max-width: 120px;
background-color: #ee7008;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 0.5rem;
}
:global(.tooltip::after) {
content: '';
position: absolute;
margin-left: -5px;
border-width: 5px;
border-style: solid;
}
:global(.tooltip-right::after) {
top: calc(50% - 5px);
left: -5px;
border-color: transparent #ee7008 transparent transparent;
}
:global(.tooltip-enter) {
animation: fadeIn 0.2s linear forwards;
}
:global(.tooltip-leave) {
animation: fadeOut 0.2s linear forwards;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateX(50px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes fadeOut {
to {
opacity: 0;
transform: translateX(-50px);
}
}
```
## API
| Props | Type | Default | Description |
| ------------------------- | ------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `content` | string | null | Text content to display in the tooltip. In development, a `console.warn` is emitted if neither `content` nor `contentSelector` is provided. |
| `contentSelector` | string | null | Selector of the content to display in the tooltip. Takes precedence over `content` when both are provided. In development, a `console.warn` is emitted if the selector matches no element in the DOM. |
| `contentActions` | object | null | Configuration of the tooltip actions (see [Content Actions](#content-actions)). Each key is a CSS selector; each value is a `ContentAction` object or an array of `ContentAction` objects, allowing multiple listeners per element. **The special `'*'` key targets the entire tooltip container and works without `contentSelector`. All other keys require `contentSelector` to be set** — if they are provided without it, a `console.warn` is emitted and the non-`'*'` actions are cleared. When set and the tooltip content (pointed to by `contentSelector`) contains focusable elements, the trigger automatically receives `tabindex="0"` (if it does not already have one) so it is reachable via keyboard — Tab focuses the trigger, then Tab again enters the tooltip content. The `tabindex` is removed when `contentActions` is unset or `destroy()` is called. |
| `containerClassName` | string | null | Class name to apply to the tooltip container. When not set, the tooltip receives the auto-generated classes `__tooltip __tooltip-{position}`. |
| `position` | string | 'top' | Position of the tooltip. Available values: 'top', 'bottom', 'left', 'right'. If the tooltip would overflow the viewport, it automatically switches to the position with the most available space. For `'left'`/`'right'`, when `width` is `'auto'`, the width shrinks to fit before switching positions (down to a minimum of 80 px). |
| `animated` | boolean | false | Flag to animate tooltip transitions. The default classes `__tooltip-enter` / `__tooltip-leave` (from `useTooltip.css`) are already wrapped in `@media (prefers-reduced-motion: no-preference)`. If you supply custom `animationEnterClassName` / `animationLeaveClassName`, wrap your own keyframes in the same media query. **Do not use `animation: none` for the `reduce` case** — it suppresses `animationend`, causing the tooltip to linger for up to 1 s before the timeout fallback fires. Use `animation-duration: 0.001ms` instead so the event fires immediately. |
| `animationEnterClassName` | string | '\_\_tooltip-enter' | Class name to apply to the tooltip enter transition. |
| `animationLeaveClassName` | string | '\_\_tooltip-leave' | Class name to apply to the tooltip leave transition. |
| `enterDelay` | number | 0 | Delay before showing the tooltip in milliseconds. |
| `leaveDelay` | number | 0 | Delay before hiding the tooltip in milliseconds. |
| `onEnter` | func | null | Callback triggered when the tooltip appears. |
| `onLeave` | func | null | Callback triggered when the tooltip disappears. |
| `offset` | number | 10 | Distance between the tooltip and the target in pixels. Minimum enforced value is 5. |
| `width` | string | 'auto' | Width of the tooltip. Use `'auto'` to let the tooltip shrink-fit the trigger width, or a CSS size value (e.g. `'200px'`) to allow it to exceed the trigger width. |
| `disabled` | boolean | false | Flag to disable the tooltip. |
| `open` | boolean | undefined | Programmatically control tooltip visibility. `true` shows the tooltip and locks it open — hover/focus events and Escape are ignored while the lock is active. `false` is a one-shot close: hides the tooltip and immediately releases the lock so hover/focus resumes normally. `undefined` (or not passed) leaves normal hover/focus behavior unchanged. Has no effect when `disabled` is `true`. |
| `touchBehavior` | string | undefined | Controls how the tooltip responds to touch events. `'hover'` mirrors mouse hover — `touchstart` shows the tooltip and `touchend`/`touchcancel` hide it. `'toggle'` toggles visibility on `touchend` on the target; a `touchstart` anywhere outside the target dismisses it. When not set (default), no touch listeners are registered. |
| `showOn` | string[]| `['mouseenter', 'focusin']` | DOM event types that show the tooltip. Any valid [event type](https://developer.mozilla.org/en-US/docs/Web/Events) can be used (e.g. `['click']` to show on click only). Changing this prop via `update()` replaces the listeners atomically. When an event type appears in both `showOn` and `hideOn`, a single toggle listener is registered instead of separate show/hide ones — first trigger shows, second hides, and so on. |
| `hideOn` | string[]| `['mouseleave', 'focusout']` | DOM event types that hide the tooltip. Pass `[]` to keep the tooltip visible until dismissed by Escape, `open: false`, or programmatic removal. Changing this prop via `update()` replaces the listeners atomically. When an event type appears in both `showOn` and `hideOn`, a single toggle listener is registered instead of separate show/hide ones — first trigger shows, second hides, and so on. |
| `ariaLabel` | string | `'Tooltip'` | Accessible label for interactive tooltips (`role="dialog"`). Override the default `"Tooltip"` value to provide a more descriptive or localized label — screen readers announce this as the dialog name. Has no effect on non-interactive tooltips (`role="tooltip"`). |
### TypeScript
The package ships TypeScript types. The main types you may need when composing options or building wrappers:
```ts
import type {
TooltipOptions,
TooltipPosition,
ContentAction,
ContentActionValue,
ContentActions
} from '@untemps/svelte-use-tooltip';
```
### Content and Content Selector
The tooltip content can be specified either by the `content` prop or the `contentSelector` prop. When both are provided, `contentSelector` takes precedence.
`content` must be a text string that will be displayed as is in the tooltip.
It's useful for most of the use cases of a tooltip however sometimes you need to display some more complex content, with interactive elements or formatted text.
To do so, you may use the `contentSelector` prop that allows to specify the selector of an element from the DOM.
The best option is to use a [template](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template) HTML element although you may also use a plain element. In this case, **it will remain in the DOM and will be cloned in the tooltip**.
### Content Actions
The `contentActions` prop allows to handle interactions within the tooltip content.
Each element inside the content parent may configure its own action since it can be queried using the key-selector.
Each value in the `contentActions` object can be either a single action object (`ContentAction`) or an array of action objects (`ContentAction[]`), allowing you to attach multiple events to the same element.
> **Note:** All selector keys except `'*'` require `contentSelector` to be set. If non-`'*'` keys are provided without a `contentSelector`, a `console.warn` is emitted and those actions are cleared. The `'*'` key (whole-tooltip listener) works without `contentSelector`.
```svelte
import { useTooltip } from '@untemps/svelte-use-tooltip';
console.log(arg),
callbackParams: ["Haha you're hovering the button 1"],
closeOnCallback: false
},
'#button2': {
eventType: 'click',
callback: (arg1, arg2) => console.log(arg1, arg2),
callbackParams: ["Haha you've clicked the", 'button 2'],
closeOnCallback: true
}
}
}}
>
Hover me
Action 1
Action 2
```
| Props | Type | Default | Description |
| ----------------- | -------- | ------- | -------------------------------------------------------------------------------------------------------- |
| `eventType` | string | null | Type of the event. All available [events](https://developer.mozilla.org/fr/docs/Web/Events) can be used. |
| `callback` | function | null | Function to be used as event handler. The callback always receives the items of `callbackParams` as leading arguments, followed by the native `Event` object as the last argument: `callback(...callbackParams, event)`. Use `event.target` or `event.currentTarget` to identify the element that triggered the interaction. |
| `callbackParams` | array | null | List of arguments to pass to the event handler as leading arguments, before the native `Event` object. |
| `closeOnCallback` | boolean | false | Flag to automatically close the tooltip when the event handler is triggered. |
#### Multiple events per element
Pass an array of action objects to attach multiple listeners to the same element:
```svelte
console.log('clicked', arg),
callbackParams: ['button 1'],
closeOnCallback: true
},
{
eventType: 'mouseenter',
callback: () => console.log('hovered button 1')
}
]
}
}}
>
Hover me
Action 1
```
All listeners attached this way are automatically removed when the tooltip is hidden or destroyed.
#### `*` selector
If you need the whole tooltip content to be interactive, you can use the special `*` key:
```svelte
import { useTooltip } from '@untemps/svelte-use-tooltip';
console.log(arg),
callbackParams: ['Haha you clicked the tooltip'],
closeOnCallback: true
}
}
}}
>
Hover me
```
If you combine the `*` selector with other events, its callback will be triggered along with the other ones.
## Development
The component can be served for development purpose on `http://localhost:5173/` running:
```bash
yarn dev
```
## Contributing
Contributions are warmly welcomed:
- Fork the repository
- Create a feature branch
- Develop the feature AND write the tests (or write the tests AND develop the feature)
- Commit your changes using [Conventional Commits](https://www.conventionalcommits.org/) with sentence-case subject (e.g. `feat: Add offset prop`)
- Submit a Pull Request