<c-tooltip>
A non-interactive text hint shown when its trigger is hovered or keyboard-focused, floating in the top layer on the inverted surface tier.
Usage
Put the element the tooltip describes in the trigger slot and the hint in the text prop. For formatted content, use the content slot instead — it overrides the prop but must stay non-interactive: a tooltip is never focusable and can hold no links or buttons. If the content needs to be clicked, use c-popover.
The tooltip shows after a short hover delay (configurable via the delay prop) and immediately on keyboard focus. The trigger must be focusable for keyboard and screen-reader users to reach the hint — a c-icon-button or c-button qualifies; a bare <span> does not.
When the described element cannot be slotted, point the trigger prop at it instead — its document ID, or the element itself via property binding. The tooltip then wires hover/focus onto that element, mirrors the aria-description there, and anchors the bubble to it. Supplying both routes is a misuse: the prop wins, the slotted element gets no wiring, and a console warning flags it.
When to use
- To name an icon-only control or clarify a truncated label.
- Never for content the user must interact with, or for information that is available nowhere else on the page for touch users — tooltips are unreliable on touch devices.
Dismissal
The tooltip hides when the pointer leaves the trigger and panel, when focus leaves the trigger, and on Escape (without moving focus). The pointer can travel from the trigger onto the tooltip without it vanishing.
Accessibility
The tooltip implements the WCAG 1.4.13 (Content on Hover or Focus) contract: dismissable, hoverable, persistent.
The tooltip content is mirrored onto the trigger (slotted or designated) as aria-description, so screen readers announce it with the trigger even while the bubble is closed. aria-describedby is not used because ARIA ID references cannot cross the shadow boundary between the light-DOM trigger and the shadow-DOM panel (ADR-0033).
Layering
The panel is a native popover in the top layer: it is never clipped by ancestor overflow and paints above modals — correct for a tooltip triggered from inside one.
Customization
Structural styling via ::part(trigger) and ::part(panel). Colours come from the inverted-surface semantic tokens (--c-surface-inverted, --c-on-surface-inverted); override the tokens to re-theme.
Examples
<template>
<div class="example-row">
<c-tooltip text="Download the report as PDF">
<c-icon-button slot="trigger" aria-label="Download" ghost>
<c-icon :path="mdiDownload" />
</c-icon-button>
</c-tooltip>
<c-tooltip text="Remove the report permanently" position="bottom">
<c-icon-button slot="trigger" aria-label="Remove" ghost>
<c-icon :path="mdiTrashCanOutline" />
</c-icon-button>
</c-tooltip>
</div>
</template>
<script setup lang="ts">
import { mdiDownload, mdiTrashCanOutline } from '@mdi/js';
</script>
API reference
<c-tooltip>
A non-interactive text hint shown when its trigger is hovered or keyboard-focused, floating in the top layer on the inverted surface tier.
Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
delay | delay | number | string | 400 | Delay before the tooltip shows on hover, in milliseconds. Keyboard focus shows the tooltip immediately, regardless of this value. Defaults to `400`. |
distance | distance | number | string | 4 | Distance from the trigger to the tooltip, in pixels. Defaults to `4`. |
open | open | boolean | false | Whether the tooltip is open. Two-way: emits `change:open`. |
position | position | CPlacement | 'top' | Preferred placement of the tooltip relative to the trigger. |
text | text | string | '' | The tooltip text. Overridden by the `content` slot when that is populated. |
trigger | trigger | HTMLElement | string | — | Designated trigger: an element elsewhere in the document that the tooltip describes — its document ID, or the element itself. The same trigger concept as the `trigger` slot, supplied by reference: the tooltip wires hover/focus, mirrors `aria-description` onto it and anchors the bubble to it. When both routes are supplied, this prop wins over the slot. |
Events
| Event | Detail | Description |
|---|---|---|
change:open | boolean | Fired whenever the tooltip shows or hides, carrying the new open state. Named `change:open`, not `update:open`: Vue's runtime silently drops `onUpdate:*` listeners on custom elements (`isModelListener`), so a template `@update:open` would never be attached. |
Slots
| Slot | Description |
|---|---|
trigger | The element the tooltip describes (e.g. a c-icon-button) |
content | Formatted tooltip content, overriding the `text` prop; must stay non-interactive (ADR-0033) |
CSS parts
Style from outside with c-tooltip::part(name) — parts are the library's only styling customization API.
| Part | Description |
|---|---|
trigger | The inline wrapper around the slotted trigger, serving as the panel's anchor |
panel | The floating tooltip bubble positioned against the trigger |
Types
Importable from the package root: import type { … } from '@cscfi/csc-ui'
CTooltipProps
export interface CTooltipProps {
/**
* Delay before the tooltip shows on hover, in milliseconds. Keyboard focus
* shows the tooltip immediately, regardless of this value. Defaults to
* `400`.
*/
delay?: number | string;
/** Distance from the trigger to the tooltip, in pixels. Defaults to `4`. */
distance?: number | string;
/** Whether the tooltip is open. Two-way: emits `change:open`. */
open?: boolean;
/** Preferred placement of the tooltip relative to the trigger. */
position?: CPlacement;
/**
* The tooltip text. Overridden by the `content` slot when that is
* populated.
* @freeform
*/
text?: string;
/**
* Designated trigger: an element elsewhere in the document that the
* tooltip describes — its document ID, or the element itself. The same
* trigger concept as the `trigger` slot, supplied by reference: the
* tooltip wires hover/focus, mirrors `aria-description` onto it and
* anchors the bubble to it. When both routes are supplied, this prop wins
* over the slot.
*/
trigger?: HTMLElement | string;
}CPlacement shared
Preferred placement of a floating panel relative to its anchor, shared by the anchor-positioned overlay components (`c-menu`, `c-tooltip`, `c-popover`). The side names the panel's position; `-start`/`-end` align the panel's edge with the anchor's on the cross axis.
export type CPlacement =
| 'bottom-end'
| 'bottom-start'
| 'bottom'
| 'left-end'
| 'left-start'
| 'left'
| 'right-end'
| 'right-start'
| 'right'
| 'top-end'
| 'top-start'
| 'top';