Tooltip
ui-tooltip shows a small label next to its trigger when the pointer enters it or it receives focus. Put the element
in ui-tooltip-trigger and the label in ui-tooltip-content. The content is a role="tooltip" element shown as a
popover="manual", so it renders in the top layer, is anchored to the trigger and does not close other popovers. It
hides on pointer leave, focus out and Escape.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Tooltip demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/button.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/tooltip.html"></import-element>
<ui-tooltip>
<ui-tooltip-trigger><ui-button variant="outline">Hover me</ui-button></ui-tooltip-trigger>
<ui-tooltip-content>Add to library</ui-tooltip-content>
</ui-tooltip>
</body>
</html>Examples
Placement
placement on ui-tooltip-content puts the tooltip top (default), bottom, left or right of the trigger. A
tooltip that does not fit flips to the opposite side.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Tooltip demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
<style>
.demo-row-tight {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: calc(var(--spacing) * 2);
}
</style>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/button.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/tooltip.html"></import-element>
<div class="demo-row-tight">
<ui-tooltip>
<ui-tooltip-trigger><ui-button variant="outline">Top</ui-button></ui-tooltip-trigger>
<ui-tooltip-content placement="top">Above</ui-tooltip-content>
</ui-tooltip>
<ui-tooltip>
<ui-tooltip-trigger><ui-button variant="outline">Right</ui-button></ui-tooltip-trigger>
<ui-tooltip-content placement="right">To the right</ui-tooltip-content>
</ui-tooltip>
<ui-tooltip>
<ui-tooltip-trigger><ui-button variant="outline">Bottom</ui-button></ui-tooltip-trigger>
<ui-tooltip-content placement="bottom">Below</ui-tooltip-content>
</ui-tooltip>
<ui-tooltip>
<ui-tooltip-trigger><ui-button variant="outline">Left</ui-button></ui-tooltip-trigger>
<ui-tooltip-content placement="left">To the left</ui-tooltip-content>
</ui-tooltip>
</div>
</body>
</html>Icon buttons
Tooltips suit icon-only buttons. Keep the button's own aria-label, because the tooltip text becomes the button's
description, not its name.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Tooltip demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
<style>
.demo-row-tight {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: calc(var(--spacing) * 2);
}
</style>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/button.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/tooltip.html"></import-element>
<div class="demo-row-tight">
<ui-tooltip>
<ui-tooltip-trigger>
<ui-button variant="ghost" size="icon" aria-label="Bold">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M6 12h9a4 4 0 0 1 0 8H6V4h8a4 4 0 0 1 0 8" /></svg>
</ui-button>
</ui-tooltip-trigger>
<ui-tooltip-content>Bold</ui-tooltip-content>
</ui-tooltip>
<ui-tooltip>
<ui-tooltip-trigger>
<ui-button variant="ghost" size="icon" aria-label="Italic">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M19 4h-9M14 20H5M15 4 9 20" /></svg>
</ui-button>
</ui-tooltip-trigger>
<ui-tooltip-content>Italic</ui-tooltip-content>
</ui-tooltip>
</div>
</body>
</html>Rich content and delay
ui-tooltip-content can hold markup such as a keyboard shortcut. delay on ui-tooltip sets the milliseconds before
the tooltip appears (default 300). Hiding is immediate.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Tooltip demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/button.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/kbd.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/tooltip.html"></import-element>
<ui-tooltip delay="0">
<ui-tooltip-trigger><ui-button variant="outline">Save</ui-button></ui-tooltip-trigger>
<ui-tooltip-content>Save draft <ui-kbd>Ctrl S</ui-kbd></ui-tooltip-content>
</ui-tooltip>
</body>
</html>Dynamic content
The content can be bound from a component's state. The trigger's description follows it.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Tooltip demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/button.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/tooltip.html"></import-element>
<import-element from="./tooltip-copy-demo.html"></import-element>
<tooltip-copy-demo></tooltip-copy-demo>
</body>
</html><custom-element name="tooltip-copy-demo">
<script>
const copy = useState({ label: "Copy link" });
function copied() {
copy.label = "Copied";
}
function reset() {
copy.label = "Copy link";
}
</script>
<ui-tooltip delay="0">
<ui-tooltip-trigger onpointerleave="reset()"><ui-button variant="outline" onclick="copied()">Share</ui-button></ui-tooltip-trigger>
<ui-tooltip-content><slot name="#copy.label"></slot></ui-tooltip-content>
</ui-tooltip>
</custom-element>API
Parts
| Part | Slot | Renders |
|---|---|---|
ui-tooltip |
Its parts, with no box of its own. | |
ui-tooltip-trigger |
(default) | An inline block around the trigger. Pointer enter and focus show the tooltip. Pointer leave, focus out and Escape hide it. |
ui-tooltip-content |
(default) | A popover="manual" element with role="tooltip", in var(--text-xs) on the foreground colour, anchored to the trigger. |
ui-tooltip attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
delay |
number | 300 |
Milliseconds before the tooltip opens. Minimum 0. |
ui-tooltip-content attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
placement |
"top" | "bottom" | "left" | "right" |
"top" |
Side of the trigger the tooltip appears on. |
CSS parts
| Element | Part | Description |
|---|---|---|
ui-tooltip-trigger |
trigger |
The wrapper that listens for pointer and focus events. |
CSS states
| Name | Description |
|---|---|
ui-tooltip-content:popover-open |
Matches while the tooltip is shown. |
Accessibility
- The content has
role="tooltip"and opens on focus as well as hover, so keyboard users see it. - Escape hides it while focus is on the trigger.
- The tooltip text is set as
aria-descriptionon each element inui-tooltip-trigger(ui-buttonpasses it to its inner button). Give the trigger its own accessible name.