Components
Tooltip
Built on top of Anchor.
Wrap the trigger in <Tooltip> and pass a stable
id. Set interestfor, commandfor,
and command="toggle-popover" on the trigger element itself (these
attributes are only valid on real invokers like
<button> or <a>). Pass a
label prop for plain text or use the content slot
for richer markup.
popover-hint.
Basics
Pass plain text via the label prop.
---import { Button, Tooltip } from "@opui/astro"---
<Tooltip label="Save your changes" id="tooltip-basic"> <Button interestfor="tooltip-basic" commandfor="tooltip-basic" command="toggle-popover">Save</Button ></Tooltip><span class="anchor tooltip" style=""> <span interestfor="tooltip-basic" ><button interestfor="tooltip-basic" commandfor="tooltip-basic" command="toggle-popover" class="button" > Save </button> </span> <span class="anchor-floating" id="tooltip-basic" popover="hint"> Save your changes </span></span>Alignment
Set the alignment prop to any valid position-area value to control where the tooltip appears.
---import { Button, Tooltip } from "@opui/astro"---
<div class="tooltip-alignment-grid"> <Tooltip label="Above" alignment="block-start" id="tooltip-top"> <Button interestfor="tooltip-top" commandfor="tooltip-top" command="toggle-popover">Top</Button > </Tooltip> <Tooltip label="Before" alignment="inline-start" id="tooltip-start"> <Button interestfor="tooltip-start" commandfor="tooltip-start" command="toggle-popover">Start</Button > </Tooltip> <Tooltip label="After" alignment="inline-end" id="tooltip-end"> <Button interestfor="tooltip-end" commandfor="tooltip-end" command="toggle-popover">End</Button > </Tooltip> <Tooltip label="Below" alignment="block-end" id="tooltip-bottom"> <Button interestfor="tooltip-bottom" commandfor="tooltip-bottom" command="toggle-popover">Bottom</Button > </Tooltip></div>
<style> .tooltip-alignment-grid { display: grid; gap: var(--size-3); grid-template-areas: ". top . " "start . end" ". bottom . "; justify-items: center; align-items: center; }
.tooltip-alignment-grid > :nth-child(1) { grid-area: top; } .tooltip-alignment-grid > :nth-child(2) { grid-area: start; } .tooltip-alignment-grid > :nth-child(3) { grid-area: end; } .tooltip-alignment-grid > :nth-child(4) { grid-area: bottom; }</style><div class="tooltip-alignment-grid"> <span class="anchor tooltip" style="--anchor-position-area: block-start"> <span interestfor="tooltip-top" ><button interestfor="tooltip-top" commandfor="tooltip-top" command="toggle-popover" class="button" > Top </button> </span> <span class="anchor-floating" id="tooltip-top" popover="hint"> Above </span> </span> <span class="anchor tooltip" style="--anchor-position-area: inline-start"> <span interestfor="tooltip-start" ><button interestfor="tooltip-start" commandfor="tooltip-start" command="toggle-popover" class="button" > Start </button> </span> <span class="anchor-floating" id="tooltip-start" popover="hint"> Before </span> </span> <span class="anchor tooltip" style="--anchor-position-area: inline-end"> <span interestfor="tooltip-end" ><button interestfor="tooltip-end" commandfor="tooltip-end" command="toggle-popover" class="button" > End </button> </span> <span class="anchor-floating" id="tooltip-end" popover="hint"> After </span> </span> <span class="anchor tooltip" style="--anchor-position-area: block-end"> <span interestfor="tooltip-bottom" ><button interestfor="tooltip-bottom" commandfor="tooltip-bottom" command="toggle-popover" class="button" > Bottom </button> </span> <span class="anchor-floating" id="tooltip-bottom" popover="hint"> Below </span> </span></div>Arrow
Set the arrow prop to render a small arrow pointing from the
tooltip toward the trigger. The arrow tracks the configured
alignment — it does not currently track
position-try-fallbacks flips at runtime.
---import { Button, Tooltip } from "@opui/astro"---
<Tooltip arrow label="Save your changes" id="tooltip-arrow"> <Button interestfor="tooltip-arrow" commandfor="tooltip-arrow" command="toggle-popover">Save</Button ></Tooltip><span class="anchor tooltip with-arrow" style=""> <span interestfor="tooltip-arrow" ><button interestfor="tooltip-arrow" commandfor="tooltip-arrow" command="toggle-popover" class="button" > Save </button> </span> <span class="anchor-floating" id="tooltip-arrow" popover="hint"> Save your changes </span></span>Rich content
Use the content slot to render markup such as <kbd> shortcuts inside the tooltip.
---import { Button, Tooltip } from "@opui/astro"---
<Tooltip id="tooltip-rich"> <Button interestfor="tooltip-rich" commandfor="tooltip-rich" command="toggle-popover">Keyboard shortcuts</Button > <Fragment slot="content"> Press <kbd>⌘</kbd> + <kbd>K</kbd> to open the command palette. </Fragment></Tooltip><span class="anchor tooltip" style=""> <span interestfor="tooltip-rich" ><button interestfor="tooltip-rich" commandfor="tooltip-rich" command="toggle-popover" class="button" > Keyboard shortcuts </button> </span> <span class="anchor-floating" id="tooltip-rich" popover="hint"> Press <kbd>⌘</kbd> + <kbd>K</kbd> to open the command palette. </span></span>API
| Prop | Type | Default | Description |
|---|---|---|---|
alignment | string | "block-start" | Any valid position-area value. Controls where the tooltip is
placed relative to the trigger. |
arrow | boolean | false | When true, renders an arrow pointing from the tooltip
toward the trigger. The arrow flips automatically with the tooltip via
position-try-fallbacks. |
id | string | auto-generated | Identifier used to wire interestfor on the trigger to the floating
element. |
label | string | — | Plain-text tooltip content. For richer markup, use the content slot instead. |
Browser support
popover-hint.
See also the full browser support guide.
Installation
@layer components.extended { :where(.tooltip) { --_tooltip-bg: light-dark(var(--gray-13), var(--gray-3)); --_tooltip-color: light-dark(var(--gray-1), var(--gray-15)); --_tooltip-offset: var(--size-2);
&>.anchor-floating { background-color: var(--_tooltip-bg); border-radius: var(--radius-2); color: var(--_tooltip-color); font-size: var(--font-size-05); line-height: 1.3; margin: var(--_tooltip-offset); max-inline-size: 240px; /* UA sets overflow: auto on [popover], which clips the arrow. */ overflow: visible; padding-block: var(--size-1); padding-inline: var(--size-2); position-area: var(--anchor-position-area, block-start); position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline; position-visibility: anchors-visible; text-align: center; text-wrap: pretty; }
/* Optional arrow pointing from the tooltip toward the trigger. Anchored to the same --anchor so it flips together with the tooltip when position-try-fallbacks kicks in. */ &.with-arrow { --_arrow-size: var(--size-2);
&>.anchor-floating { /* Reserve space so the arrow doesn't overlap the trigger. */ --_tooltip-offset: calc(var(--size-2) + var(--_arrow-size) / 2); }
&>.anchor-floating::before { background-color: var(--_tooltip-bg); block-size: var(--_arrow-size); content: ""; inline-size: var(--_arrow-size); inset-block-end: calc(var(--_arrow-size) / -2); inset-inline-start: 50%; position: absolute; rotate: 45deg; translate: -50% 0; } }
/* Fade */ &>.anchor-floating[popover] { opacity: 0; transition: display 0.15s allow-discrete, opacity 0.15s var(--ease-out-1), overlay 0.15s allow-discrete;
&:popover-open { opacity: 1;
@starting-style { opacity: 0; } } } }}@layer components.root { :where(.anchor) { anchor-name: --anchor; anchor-scope: --anchor; display: inline-block; inline-size: fit-content;
/* Always-visible */ &>.anchor-floating:not([popover]) { block-size: max-content; inline-size: max-content; position: absolute; position-anchor: --anchor; position-area: var(--anchor-position-area, start end); translate: var(--_anchor-tx, 0) var(--_anchor-ty, 0); }
/* Hover-triggered */ &>.anchor-floating[popover] { inset: unset; margin: 0; position: absolute; position-area: var(--anchor-position-area, start end); translate: var(--_anchor-tx, 0) var(--_anchor-ty, 0); } }}