Tooltip
A text label that appears when a user hovers, focuses, or touches an element.
import { component$ } from '@builder.io/qwik';
import { Tooltip } from '@qwik-ui/headless';
export default component$(() => {
return (
<Tooltip.Root gutter={4} flip>
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
<Tooltip.Panel class="tooltip-panel">Tooltip content here</Tooltip.Panel>
</Tooltip.Root>
);
});
- Opens on hover or focus
- Closes on trigger activation or Escape key press
- Customizable open/close delays
- Optional arrow component
- Always portaled content
- Accessibility with ARIA roles and keyboard interactions
- Flipping to avoid overflow
- Automatic placement adjustment
The Qwik UI Tooltip component provides additional information or context on hover, focus, or touch. It ensures accessibility and positioning with built-in ARIA roles and automatic placement adjustments.
Building blocks
Anatomy Table
Component | Description |
Tooltip.Root | The parent container for the tooltip trigger and panel. |
Tooltip.Trigger | An element that opens the tooltip when interacted with. |
Tooltip.Panel | An HTML element that contains the tooltip content. |
Tooltip.Arrow | An optional arrow component to point to the trigger element. |
What is a Tooltip?
A tooltip is a small text label that appears when a user hovers over, focuses on, or touches an element. It provides additional information or context.
When would I use a tooltip?
Tooltips are useful for displaying contextual information or additional details about an element without cluttering the UI. They enhance user experience by providing necessary information only when needed.
Use case examples
Component | Description |
Form Field | Provide additional information or guidance about a form field. |
Button | Explain what an action button does. |
Icon | Give more context or definition to an icon. |
Caveats
Styling open tooltips
Use the data-open
and data-closed
attributes on the <Tooltip.Panel>
component to specifically style the tooltip when it's open.
Tooltip Behavior
Tooltips show when hovering over or focusing on the trigger element and dismiss when moving the mouse away or losing focus.
Floating Behavior
By default, the Qwik UI Tooltip will float above the trigger component.
import { component$ } from '@builder.io/qwik';
import { Tooltip } from '@qwik-ui/headless';
export default component$(() => {
return (
<Tooltip.Root gutter={4} flip>
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
<Tooltip.Panel class="tooltip-panel">Floating Tooltip content here</Tooltip.Panel>
</Tooltip.Root>
);
});
To make a tooltip float, we use JavaScript to choose where the tooltip should be positioned.
Custom Floating Position
By default, tooltips will float above the trigger component.
When setting placement
on the root, you can customize the position of the tooltip.
import { component$, useSignal } from '@builder.io/qwik';
import { Tooltip } from '@qwik-ui/headless';
export default component$(() => {
const placement = useSignal<'top' | 'right' | 'bottom' | 'left'>('top');
return (
<div>
<label for="placement">Select Tooltip Placement: </label>
<select
id="placement"
value={placement.value}
onChange$={(e) =>
(placement.value = (e.target as HTMLSelectElement).value as
| 'top'
| 'right'
| 'bottom'
| 'left')
}
>
<option value="top">Top</option>
<option value="right">Right</option>
<option value="bottom">Bottom</option>
<option value="left">Left</option>
</select>
<Tooltip.Root key={placement.value} gutter={4} flip placement={placement.value}>
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
<Tooltip.Panel
aria-label={`Tooltip content on the ${placement.value}`}
class="tooltip-panel"
>
Tooltip content on the {placement.value}
</Tooltip.Panel>
</Tooltip.Root>
</div>
);
});
Above we have set the placement
prop to right
, so the <Tooltip.Panel>
will be positioned to the right of the trigger.
Flip
Enabled by default, we can use the flip
prop to flip its position based on the available space in the viewport.
import { component$ } from '@builder.io/qwik';
import { Tooltip } from '@qwik-ui/headless';
export default component$(() => {
return (
<Tooltip.Root gutter={4} flip>
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
<Tooltip.Panel class="tooltip-panel">
Tooltip content with flip enabled
</Tooltip.Panel>
</Tooltip.Root>
);
});
To disable flipping, set flip={false}
on the <Tooltip.Root>
.
Gutter
The gutter property defines the space between the anchor element and the floating element.
import { component$ } from '@builder.io/qwik';
import { Tooltip } from '@qwik-ui/headless';
export default component$(() => {
return (
<Tooltip.Root gutter={20} flip>
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
<Tooltip.Panel class="tooltip-panel">Tooltip content with gutter</Tooltip.Panel>
</Tooltip.Root>
);
});
Styling
Styles can be added normally like any other component in Qwik UI, such as adding a class.
If Tailwind is the framework of choice, then styles can be added using the arbitrary variant syntax or @apply command.
import { component$ } from '@builder.io/qwik';
import { Tooltip } from '@qwik-ui/headless';
import '../snippets/styling.css';
export default component$(() => {
return (
<Tooltip.Root delayDuration={800} gutter={4} flip>
<Tooltip.Trigger class="custom-trigger">Hover or Focus me</Tooltip.Trigger>
<Tooltip.Panel class="custom-tooltip-panel">Tooltip content here</Tooltip.Panel>
</Tooltip.Root>
);
});
Animations
Tooltips rely on animations and transitions to provide smooth entry and exit effects. Like the Popover, tooltips benefit from modern CSS capabilities that allow animating between display: none and display: block. This ensures the tooltip remains visible for the entire duration of the animation.
Keyframe Animation Example
import { component$, useStyles$ } from '@builder.io/qwik';
import { Tooltip } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(`
.tooltip-animation {
animation: tooltip-shrink 0.4s ease-in-out forwards;
}
.tooltip-animation:popover-open {
animation: tooltip-grow 0.5s ease-in-out forwards;
}
@keyframes tooltip-shrink {
from {
transform: scale(1);
display: block;
}
to {
transform: scale(0);
display: none;
}
}
@keyframes tooltip-grow {
from {
transform: scale(0);
}
to {
transform: scale(1);
}
}`);
return (
<Tooltip.Root gutter={4} flip>
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
<Tooltip.Panel class="tooltip-animation">
Animated tooltip content here
</Tooltip.Panel>
</Tooltip.Root>
);
});
Keyframes are used for complex entry and exit animations. In this case:
tooltip-grow
animates the tooltip to grow from scale 0 to scale 1 when it opens.
tooltip-shrink
animates the tooltip to shrink from scale 1 to scale 0 when it closes, eventually setting display: none
.
Transition declarations
Transitions are ideal for animating properties like opacity and scale for smoother interactions:
import { component$, useStyles$ } from '@builder.io/qwik';
import { Tooltip } from '@qwik-ui/headless';
export default component$(() => {
useStyles$(`
.tooltip-transition {
opacity: 0;
transform: scaleX(0);
transition: all 0.7s ease;
transition-behavior: allow-discrete;
}
.tooltip-transition:popover-open {
opacity: 1;
transform: scaleX(1);
}
@starting-style {
.tooltip-transition:popover-open {
opacity: 0;
transform: scaleX(0);
}
}`);
return (
<Tooltip.Root gutter={4} flip>
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
<Tooltip.Panel class="tooltip-transition">
Tooltip content with transition
</Tooltip.Panel>
</Tooltip.Root>
);
});
Here, transitions handle smooth opacity and scale changes. The transition-behavior: allow-discrete
ensures that display
and overlay
animate properly.
Events
The tooltip contains a onOpenChange$
event that runs when the tooltip opens or closes.
This can be used to trigger additional actions when the tooltip is opened or closed.
import { component$, useSignal } from '@builder.io/qwik';
import { Tooltip } from '@qwik-ui/headless';
export default component$(() => {
const tooltipState = useSignal<'open' | 'closed'>('closed');
return (
<>
<Tooltip.Root gutter={4} onOpenChange$={(e) => (tooltipState.value = e)} flip>
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
<Tooltip.Panel aria-label="Tooltip content">
<Tooltip.Arrow width={10} height={5} />
Tooltip content here
</Tooltip.Panel>
</Tooltip.Root>
The tooltip is {tooltipState.value}
</>
);
});
Additional References
Qwik UI aims to be in line with the standard whenever possible. Our goal is to empower Qwik developers to create amazing experiences for their users.
To read more about tooltips you can check it out on:
Tooltip Root
Prop | Type | Description |
---|---|---|
id | string | Tooltip's id. Should match the tooltip target. |
delayDuration | number | A value that determines how long before the tooltip will be opened once triggered in milliseconds. |
flip | boolean | Flips the placement of the tooltip when it starts to collide with the boundaries. |
gutter | number | The space between the trigger element and the tooltip. |
data-closing | selector | Style the element when the tooltip is closing. This occurs when the popover has a delay set. |
data-closed | selector | Style the element when the tooltip is closed. |
data-opening | selector | Style the element when the tooltip is in the process of opening. This occurs when the popover has a delay set. |
data-open | selector | Style the element when the tooltip is open. |
onOpenChange$ | QRL QRL<(state: "open" | "closed") => void> | QRL handler that runs when the tooltip opens or closes. |
Tooltip Components
Prop | Type | Description |
---|---|---|
Tooltip.Trigger |
| The element that triggers the tooltip. |
Tooltip.Panel |
| The container for the tooltip content. |
Tooltip.Arrow |
| An optional arrow component for the tooltip. |
Example Usages
Basic:
import { component$ } from '@builder.io/qwik';
import { Tooltip } from '@qwik-ui/headless';
export default component$(() => {
return (
<Tooltip.Root gutter={4} flip>
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
<Tooltip.Panel aria-label="Tooltip content">
<Tooltip.Arrow width={10} height={5} />
Tooltip content here
</Tooltip.Panel>
</Tooltip.Root>
);
});
Complex HTML:
Tooltip Title
This is a tooltip with complex HTML content, including:
- List item 1
- List item 2
- List item 3
import { component$ } from '@builder.io/qwik';
import { Tooltip } from '@qwik-ui/headless';
export default component$(() => {
return (
<Tooltip.Root gutter={4} flip placement="bottom">
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
<Tooltip.Panel aria-label="Complex Tooltip content">
<Tooltip.Arrow width={10} height={5} />
<div>
<h3>Tooltip Title</h3>
<p>This is a tooltip with complex HTML content, including:</p>
<ul>
<li>List item 1</li>
<li>List item 2</li>
<li>List item 3</li>
</ul>
</div>
</Tooltip.Panel>
</Tooltip.Root>
);
});