Tooltip
<div role="tooltip">
A short label that appears on hover or keyboard focus. Best used on icon buttons, truncated text, and elements that need brief clarification. For rich content (forms, links, actions) use Popover instead.
Overview
Preview
Tooltip on top
Tooltip on bottom
Left tooltip
Right tooltip
Delete item
Top (default)
Preview
Tooltip text
html
<div class="relative inline-flex group">
<button class="...">Hover me</button>
<div
class="pointer-events-none absolute bottom-full left-1/2 mb-2 -translate-x-1/2
whitespace-nowrap rounded-md bg-zinc-800 border border-zinc-700
px-2.5 py-1.5 text-xs text-zinc-200 shadow-xl
opacity-0 translate-y-1 transition-all duration-150
group-hover:opacity-100 group-hover:translate-y-0 z-20"
role="tooltip"
>
Tooltip text
<!-- Arrow -->
<span class="absolute top-full left-1/2 -translate-x-1/2 border-4 border-transparent border-t-zinc-700"></span>
</div>
</div>Positions
All four positions follow the same pattern — change the anchor class and arrow:
html
<!-- Top -->
<div class="absolute bottom-full left-1/2 mb-2 -translate-x-1/2 ... translate-y-1 group-hover:translate-y-0">
<span class="absolute top-full left-1/2 -translate-x-1/2 border-4 border-transparent border-t-zinc-700"></span>
</div>
<!-- Bottom -->
<div class="absolute top-full left-1/2 mt-2 -translate-x-1/2 ... -translate-y-1 group-hover:translate-y-0">
<span class="absolute bottom-full left-1/2 -translate-x-1/2 border-4 border-transparent border-b-zinc-700"></span>
</div>
<!-- Left -->
<div class="absolute right-full top-1/2 mr-2 -translate-y-1/2 ... translate-x-1 group-hover:translate-x-0">
<span class="absolute left-full top-1/2 -translate-y-1/2 border-4 border-transparent border-l-zinc-700"></span>
</div>
<!-- Right -->
<div class="absolute left-full top-1/2 ml-2 -translate-y-1/2 ... -translate-x-1 group-hover:translate-x-0">
<span class="absolute right-full top-1/2 -translate-y-1/2 border-4 border-transparent border-r-zinc-700"></span>
</div>On an icon button
Preview
Delete item
html
<!-- aria-label + role="tooltip" gives full screen reader support -->
<div class="relative inline-flex group">
<button aria-label="Delete item" aria-describedby="tooltip-delete" class="...">
<svg ...><!-- icon --></svg>
</button>
<div id="tooltip-delete" role="tooltip" class="... opacity-0 group-hover:opacity-100">
Delete item
</div>
</div>Vue composable (reusable)
vue
<!-- components/OxTooltip.vue -->
<script setup>
defineProps({
text: { type: String, required: true },
pos: { type: String, default: 'top' }, // top | bottom | left | right
})
</script>
<template>
<div class="relative inline-flex group">
<slot />
<div
class="pointer-events-none absolute z-20 whitespace-nowrap rounded-md border border-zinc-700
bg-zinc-800 px-2.5 py-1.5 text-xs text-zinc-200 shadow-xl
transition-all duration-150 opacity-0 group-hover:opacity-100"
:class="{
'bottom-full left-1/2 mb-2 -translate-x-1/2 translate-y-1 group-hover:translate-y-0': pos === 'top',
'top-full left-1/2 mt-2 -translate-x-1/2 -translate-y-1 group-hover:translate-y-0': pos === 'bottom',
'right-full top-1/2 mr-2 -translate-y-1/2 translate-x-1 group-hover:translate-x-0': pos === 'left',
'left-full top-1/2 ml-2 -translate-y-1/2 -translate-x-1 group-hover:translate-x-0': pos === 'right',
}"
role="tooltip"
>
{{ text }}
</div>
</div>
</template>
<!-- Usage -->
<OxTooltip text="Save document" pos="top">
<button class="..."><SaveIcon /></button>
</OxTooltip>Accessibility notes
- Add
role="tooltip"to the tooltip element andaria-describedbyon the trigger pointing to the tooltip'sid - For icon-only buttons, also add
aria-labelso the button itself has an accessible name - Tooltips must appear on keyboard focus, not just hover — the
group-focus-within:opacity-100variant handles this: add it alongsidegroup-hover:opacity-100 - Tooltip text should be brief (under ~10 words). For anything richer use Popover
- Never put interactive content (links, buttons) inside a tooltip — use a Popover instead