An open API service indexing awesome lists of open source software.

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

Awesome Lists containing this project

README

          


svelte-use-tooltip



Svelte action to display a tooltip

[![npm](https://img.shields.io/npm/v/@untemps/svelte-use-tooltip?style=for-the-badge)](https://www.npmjs.com/package/@untemps/svelte-use-tooltip)
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/untemps/svelte-use-tooltip/publish.yml?style=for-the-badge)](https://github.com/untemps/svelte-use-tooltip/actions)
[![Codecov](https://img.shields.io/codecov/c/github/untemps/svelte-use-tooltip?style=for-the-badge)](https://codecov.io/gh/untemps/svelte-use-tooltip)

## Demo


LIVE 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