Skip to content
ShineUI
Install

Tooltip

One line, on hover.

<sui-tooltip>OverlaysStable

About

One-line capsule that explains an icon button or reveals a truncated cell. It wraps its trigger and shows on hover after a short delay, or at once on keyboard focus; the brand tone sits on light surfaces and the light tone on brand or dark chrome. Reach for it for a label, never for content or actions.

Usage

<sui-tooltip content="Bold"> <button type="button" aria-label="Bold" style="width:34px;height:34px;border-radius:8px;border:0;background:none;display:inline-flex;align-items:center;justify-content:center;color:var(--ink-muted);cursor:pointer"><i class="fa-solid fa-bold" style="font-size:13px" aria-hidden="true"></i></button> </sui-tooltip> <script type="module"> import { defineCustomElements } from "@shineui/core/loader"; import "@shineui/core/shineui.css"; defineCustomElements(); const el = document.querySelector("sui-tooltip"); el.addEventListener("suiClose", (e) => console.log(e.detail)); </script>
import { SuiTooltip } from "@shineui/react"; import "@shineui/core/shineui.css"; export function Example() { return ( <SuiTooltip content="Bold" onSuiClose={(e) => console.log(e.detail)}> <button type="button" aria-label="Bold" style="width:34px;height:34px;border-radius:8px;border:0;background:none;display:inline-flex;align-items:center;justify-content:center;color:var(--ink-muted);cursor:pointer"><i class="fa-solid fa-bold" style="font-size:13px" aria-hidden="true"></i></button> </SuiTooltip> ); }
<script setup> import { SuiTooltip } from "@shineui/vue"; import "@shineui/core/shineui.css"; const onChange = (e) => console.log(e.detail); </script> <template> <SuiTooltip content="Bold" @sui-close="onChange"><button type="button" aria-label="Bold" style="width:34px;height:34px;border-radius:8px;border:0;background:none;display:inline-flex;align-items:center;justify-content:center;color:var(--ink-muted);cursor:pointer"><i class="fa-solid fa-bold" style="font-size:13px" aria-hidden="true"></i></button></SuiTooltip> </template>
import { Component } from "@angular/core"; import { SuiTooltip } from "@shineui/angular"; @Component({ standalone: true, imports: [SuiTooltip], template: `<sui-tooltip content="Bold" [(open)]="open" (suiClose)="onChange($event)"><button type="button" aria-label="Bold" style="width:34px;height:34px;border-radius:8px;border:0;background:none;display:inline-flex;align-items:center;justify-content:center;color:var(--ink-muted);cursor:pointer"><i class="fa-solid fa-bold" style="font-size:13px" aria-hidden="true"></i></button></sui-tooltip>`, }) export class Example { open = false; onChange(e: CustomEvent) { console.log(e.detail); } }

Basic

The capsule is role="tooltip" and the first focusable in the trigger gets aria-describedby, so it describes and never names: an icon-only control still needs its own aria-label. The content slot takes a rich one-liner. The triggers are plain buttons: sui-icon-button draws its own capsule, so wrapping one shows two.

Riverbend Dental Group, overdue 15 days
<div style="padding-top:40px;display:flex;gap:40px;align-items:center;font-size:13px"> <sui-tooltip content="Bold"> <button type="button" aria-label="Bold" style="width:34px;height:34px;border-radius:8px;border:0;background:none;display:inline-flex;align-items:center;justify-content:center;color:var(--ink-muted);cursor:pointer"><i class="fa-solid fa-bold" style="font-size:13px" aria-hidden="true"></i></button> </sui-tooltip> <sui-tooltip> <button type="button" style="display:inline-block;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border:0;border-bottom:1px dotted var(--border-strong);background:none;font:inherit;color:inherit;padding:0">Riverbend Dental Group</button> <span slot="content"><b>Riverbend Dental Group</b>, overdue 15 days</span> </sui-tooltip> </div>

Positions

position is the preferred side; the capsule flips to the opposite side when the viewport has no room, and to the roomier side when neither fits. While shown it paints in the top layer, so a sticky bar or a transformed card cannot cover or displace it. open pins a capsule, which is how these four stay up.

<div style="padding:44px 60px;display:inline-flex;gap:70px;align-items:center"> <sui-tooltip open content="Top" position="top"><button type="button" aria-label="Locked cell" style="width:34px;height:34px;border-radius:8px;border:1px solid var(--border-strong);background:none;display:inline-flex;align-items:center;justify-content:center;color:var(--ink-muted)" ><i class="fa-solid fa-lock" style="font-size:13px" aria-hidden="true"></i></button></sui-tooltip> <sui-tooltip open content="Right" position="right"><button type="button" aria-label="Locked cell" style="width:34px;height:34px;border-radius:8px;border:1px solid var(--border-strong);background:none;display:inline-flex;align-items:center;justify-content:center;color:var(--ink-muted)" ><i class="fa-solid fa-lock" style="font-size:13px" aria-hidden="true"></i></button></sui-tooltip> <sui-tooltip open content="Bottom" position="bottom"><button type="button" aria-label="Locked cell" style="width:34px;height:34px;border-radius:8px;border:1px solid var(--border-strong);background:none;display:inline-flex;align-items:center;justify-content:center;color:var(--ink-muted)" ><i class="fa-solid fa-lock" style="font-size:13px" aria-hidden="true"></i></button></sui-tooltip> <sui-tooltip open content="Left" position="left"><button type="button" aria-label="Locked cell" style="width:34px;height:34px;border-radius:8px;border:1px solid var(--border-strong);background:none;display:inline-flex;align-items:center;justify-content:center;color:var(--ink-muted)" ><i class="fa-solid fa-lock" style="font-size:13px" aria-hidden="true"></i></button></sui-tooltip> </div>

Light tone

tone="light" is the surface capsule for brand or dark chrome, such as a sidebar or a top bar. The default tone is brand.

<div style="padding:44px 20px 20px;background:var(--surface-navy);border-radius:var(--radius-lg);display:inline-flex"> <sui-tooltip open tone="light" content="Sign out" position="top"> <button type="button" aria-label="Sign out" style="width:34px;height:34px;border-radius:8px;border:1px solid var(--border-inverse);background:none;display:inline-flex;align-items:center;justify-content:center;color:var(--ink-inverse-muted)"><i class="fa-solid fa-arrow-right-from-bracket" style="font-size:13px" aria-hidden="true"></i></button> </sui-tooltip> </div>

Delays

A pointer crossing the row shows nothing until it settles for open-delay; the last control has none. close-delay holds the capsule after mouse-out and is zero by default.

<div style="padding-top:44px;display:inline-flex;gap:4px"> <sui-tooltip content="Bold"><button type="button" aria-label="Bold" style="width:34px;height:34px;border-radius:8px;border:0;background:none;display:inline-flex;align-items:center;justify-content:center;color:var(--ink-muted);cursor:pointer"><i class="fa-solid fa-bold" style="font-size:13px" aria-hidden="true"></i></button></sui-tooltip> <sui-tooltip content="Italic"><button type="button" aria-label="Italic" style="width:34px;height:34px;border-radius:8px;border:0;background:none;display:inline-flex;align-items:center;justify-content:center;color:var(--ink-muted);cursor:pointer"><i class="fa-solid fa-italic" style="font-size:13px" aria-hidden="true"></i></button></sui-tooltip> <sui-tooltip content="Underline" close-delay="400"><button type="button" aria-label="Underline" style="width:34px;height:34px;border-radius:8px;border:0;background:none;display:inline-flex;align-items:center;justify-content:center;color:var(--ink-muted);cursor:pointer"><i class="fa-solid fa-underline" style="font-size:13px" aria-hidden="true"></i></button></sui-tooltip> <sui-tooltip content="Attach a file" open-delay="0"><button type="button" aria-label="Attach a file" style="width:34px;height:34px;border-radius:8px;border:0;background:none;display:inline-flex;align-items:center;justify-content:center;color:var(--ink-muted);cursor:pointer"><i class="fa-solid fa-paperclip" style="font-size:13px" aria-hidden="true"></i></button></sui-tooltip> </div>

Suppressed

A tooltip with no content, and a disabled one, never paint a capsule, so a grid can bind content to the clipped cells alone. The wrapper stays, so nothing moves.

<div style="padding-top:44px;display:flex;gap:40px;align-items:center;font-size:13px"> <sui-tooltip content="Riverbend Dental Group"> <button type="button" style="display:inline-block;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border:0;border-bottom:1px dotted var(--border-strong);background:none;font:inherit;color:inherit;padding:0">Riverbend Dental Group</button> </sui-tooltip> <sui-tooltip> <button type="button" style="display:inline-block;border:0;background:none;font:inherit;color:inherit;padding:0">Short name</button> </sui-tooltip> <sui-tooltip disabled content="Never shown"> <button type="button" style="display:inline-block;border:0;background:none;font:inherit;color:var(--ink-muted);padding:0">Suppressed</button> </sui-tooltip> </div>

Events

Hover is internal state and emits nothing. Escape on a pinned capsule emits the cancelable suiClose, then clears open; focus the box and press Escape.

Pinned.
<div style="padding-top:44px;display:flex;gap:20px;align-items:center"> <sui-tooltip id="tip-events" open content="Reconciled through Jul 31" position="top"><button type="button" aria-label="Locked cell" style="width:34px;height:34px;border-radius:8px;border:1px solid var(--border-strong);background:none;display:inline-flex;align-items:center;justify-content:center;color:var(--ink-muted)" ><i class="fa-solid fa-lock" style="font-size:13px" aria-hidden="true"></i></button></sui-tooltip> <span id="tip-log" style="font:460 13px/1.6 var(--font-sans);color:var(--ink-muted)">Pinned.</span> </div>
// setup(root): properties and events setup(root) { const tip = root.querySelector('#tip-events'); const log = root.querySelector('#tip-log'); tip.addEventListener('suiClose', (e) => { log.textContent = 'suiClose (' + e.detail + '). Unpinned.'; }); }

Keyboard

KeyAction
TabFocus landing on the trigger shows the capsule at once; focus leaving hides it.
EscapeHides the capsule. A pinned capsule emits suiClose first and stays if the event is refused.

API

<sui-tooltip>

Properties

PropertyAttributeTypeDefaultDescription
closeDelayclose-delaynumber0Delay in ms before hiding after mouse-out. Zero by default: the capsule is pointer-events: none, so unlike a hover card there is nothing for the pointer to travel to.
contentcontentstringstring | undefinedCapsule text. For rich one-liners use the content slot. Empty shows nothing at all, so a grid can bind it to the clipped text alone. Keep it to one short line.
disableddisabledbooleanfalseSuppresses the capsule without removing the wrapper, which would change the layout.
openopenbooleanfalsePins the capsule open regardless of hover (demos, specs). Mutable; Escape clears it. Hover is internal state and never writes this prop, and there is no suiOpen: the element never opens itself.
openDelayopen-delaynumber350Hover open delay in ms, matching sui-popover's hover card. Keyboard focus never waits. While a popup the trigger opened is up (a select's list, a menu, a calendar), hover and focus show nothing, and a capsule already up goes.
positionposition"bottom" | "left" | "right" | "top"'top'Preferred side; flips to the opposite side when the viewport has no room there, and to whichever side has more room when neither fits. While shown the capsule paints in the browser's top layer, above toasts and every other surface, so no clipping ancestor cuts it off, no transformed ancestor moves it, and no stacking context (a sticky toolbar, a dialog) paints over it.
tonetone"brand" | "light"'brand'Capsule ground: brand (the default) paints the brand fill under its own ink, for light surfaces; light is a surface capsule with a hairline, for brand or dark chrome. The word the rails and the toolbar use for the ground they paint, not the role tone of the buttons. Reflected, as every tone in the library is.

Events

EventDetailReactVueDescription
suiCloseSuiCloseReason"cancel" | "close-button" | "escape" | "outside" | "pick" | "scrim" | "trigger"onSuiClose@sui-closeFires before Escape unpins the capsule; detail is always 'escape', the only path on which this element writes open itself. Cancelable: preventDefault() keeps the capsule pinned. It does not bubble.

Slots

SlotDescription
(default)The hovered element (icon, button, truncated text).
contentRich one-line capsule content; used alongside or instead of the content prop.

Types

SuiCloseReason typeWhy a dismissible surface is closing. Detail of the cancelable suiClose. A consumer expresses "a stray backdrop click must not close this" by calling preventDefault() on the reason it does not accept, which is why none of these needs a prop of its own.
No members.

Theming

Every design token this element can render with, read from its own stylesheets and the ones it imports. Set a token on :root or on any ancestor and every use below follows it. The values shown are the ones in the theme you are viewing. The list is read per stylesheet, so an element that imports a shared drawing module lists that module's tokens too, whether or not it paints with all of them.

See also