Tailwind v4MIT licensed

Tailwind Liquid Glass Tooltip Popover

A capsule tooltip that frosts the text behind it instead of hiding it. The port's discipline is the pairing: every group-hover: has a group-focus-visible: twin, so the hint is reachable by keyboard — the single most commonly skipped requirement in tooltip components.

Live Demo
Plain CSSTailwind v4
Try it

Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time

Untitled UI React · Affiliate link

Get Untitled UI Pro

The code

<section class="lgt-11 grid w-full min-h-svh place-items-center px-6 py-15 font-lgt11-sans bg-[image:url('https://picsum.photos/seed/lgtip/1100/800')] bg-cover bg-center bg-fixed" aria-label="Tailwind liquid glass tooltip demo">
  <p class="max-w-[44ch] text-center text-[22px] leading-loose text-white [text-shadow:0_1px_10px_rgba(0,0,0,.5)]">
    Your plan renews on the
    <span tabindex="0" class="group relative cursor-help font-extrabold text-lgt11-accent outline-none border-b-2 border-dotted border-white/50 focus-visible:rounded focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-white">14th<span role="tooltip" class="pointer-events-none invisible absolute bottom-[calc(100%+12px)] left-1/2 z-5 w-max max-w-[220px] -translate-x-1/2 translate-y-1.5 rounded-[14px] border border-white/40 bg-white/16 px-3.25 py-2.25 text-[13px] font-semibold leading-snug text-white opacity-0 backdrop-blur-[16px] backdrop-saturate-180 shadow-[inset_0_1px_0_rgba(255,255,255,.5),0_16px_34px_-18px_rgba(0,0,0,.7)] transition-[opacity,transform,visibility] duration-250 [text-shadow:none] group-hover:visible group-hover:translate-y-0 group-hover:opacity-100 group-focus-visible:visible group-focus-visible:translate-y-0 group-focus-visible:opacity-100 motion-reduce:transition-[opacity,visibility] after:absolute after:top-full after:left-1/2 after:size-3 after:-translate-x-1/2 after:-translate-y-[5px] after:rotate-45 after:border-r after:border-b after:border-white/40 after:bg-inherit">Auto-renews &middot; cancel anytime up to 24h before</span></span>.
    You've used
    <span tabindex="0" class="group relative cursor-help font-extrabold text-lgt11-accent outline-none border-b-2 border-dotted border-white/50 focus-visible:rounded focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-white">68%<span role="tooltip" class="pointer-events-none invisible absolute bottom-[calc(100%+12px)] left-1/2 z-5 w-max max-w-[220px] -translate-x-1/2 translate-y-1.5 rounded-[14px] border border-white/40 bg-white/16 px-3.25 py-2.25 text-[13px] font-semibold leading-snug text-white opacity-0 backdrop-blur-[16px] backdrop-saturate-180 shadow-[inset_0_1px_0_rgba(255,255,255,.5),0_16px_34px_-18px_rgba(0,0,0,.7)] transition-[opacity,transform,visibility] duration-250 [text-shadow:none] group-hover:visible group-hover:translate-y-0 group-hover:opacity-100 group-focus-visible:visible group-focus-visible:translate-y-0 group-focus-visible:opacity-100 motion-reduce:transition-[opacity,visibility] after:absolute after:top-full after:left-1/2 after:size-3 after:-translate-x-1/2 after:-translate-y-[5px] after:rotate-45 after:border-r after:border-b after:border-white/40 after:bg-inherit">34 GB of your 50 GB quota</span></span>
    of storage this cycle, and
    <span tabindex="0" class="group relative cursor-help font-extrabold text-lgt11-accent outline-none border-b-2 border-dotted border-white/50 focus-visible:rounded focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-white">3 seats<span role="tooltip" class="pointer-events-none invisible absolute bottom-[calc(100%+12px)] left-1/2 z-5 w-max max-w-[220px] -translate-x-1/2 translate-y-1.5 rounded-[14px] border border-white/40 bg-white/16 px-3.25 py-2.25 text-[13px] font-semibold leading-snug text-white opacity-0 backdrop-blur-[16px] backdrop-saturate-180 shadow-[inset_0_1px_0_rgba(255,255,255,.5),0_16px_34px_-18px_rgba(0,0,0,.7)] transition-[opacity,transform,visibility] duration-250 [text-shadow:none] group-hover:visible group-hover:translate-y-0 group-hover:opacity-100 group-focus-visible:visible group-focus-visible:translate-y-0 group-focus-visible:opacity-100 motion-reduce:transition-[opacity,visibility] after:absolute after:top-full after:left-1/2 after:size-3 after:-translate-x-1/2 after:-translate-y-[5px] after:rotate-45 after:border-r after:border-b after:border-white/40 after:bg-inherit">2 active, 1 pending invite</span></span>
    are assigned.
  </p>
</section>
@import "tailwindcss";

@theme {
  --color-lgt11-accent: #7fd7ea;
  --color-lgt11-accent: oklch(0.85 0.13 200);
  --font-lgt11-sans: 'Manrope', system-ui, sans-serif;
}

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

Compiles in the browser — perfect for a CodePen or a quick test, not for production.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-lgt11-accent: #7fd7ea;
  --color-lgt11-accent: oklch(0.85 0.13 200);
  --font-lgt11-sans: 'Manrope', system-ui, sans-serif;
}
3Fonts used by this demooptional — skip if you have your own type stack
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;600;800&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • Every group-hover: is typed with a group-focus-visible: twin, which is the entire accessibility argument for this component.
  • invisible plus group-hover:visible keeps the bubble out of the accessibility tree when idle — opacity-0 alone does not.
  • The arrow uses after:bg-inherit, so retinting the bubble retints the arrow with no second value to maintain.
  • Three tooltips share one class string verbatim; in a component framework this is one component, and in raw HTML it is one copy-paste.
  • motion-reduce: narrows the transition to opacity and visibility, so the hint still appears but stops travelling.
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Liquid Glass Tooltip Popover
Source: https://codefronts.com/design-styles/tailwind-liquid-glass-effects/tailwind-liquid-glass-tooltip-popover/

A capsule tooltip that frosts the text behind it instead of hiding it. The port's discipline is the pairing: every group-hover: has a group-focus-visible: twin, so the hint is reachable by keyboard &mdash; the single most commonly skipped requirement in tooltip components.
## HTML
```html
<section class="lgt-11 grid w-full min-h-svh place-items-center px-6 py-15 font-lgt11-sans bg-[image:url('https://picsum.photos/seed/lgtip/1100/800')] bg-cover bg-center bg-fixed" aria-label="Tailwind liquid glass tooltip demo">
  <p class="max-w-[44ch] text-center text-[22px] leading-loose text-white [text-shadow:0_1px_10px_rgba(0,0,0,.5)]">
    Your plan renews on the
    <span tabindex="0" class="group relative cursor-help font-extrabold text-lgt11-accent outline-none border-b-2 border-dotted border-white/50 focus-visible:rounded focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-white">14th<span role="tooltip" class="pointer-events-none invisible absolute bottom-[calc(100%+12px)] left-1/2 z-5 w-max max-w-[220px] -translate-x-1/2 translate-y-1.5 rounded-[14px] border border-white/40 bg-white/16 px-3.25 py-2.25 text-[13px] font-semibold leading-snug text-white opacity-0 backdrop-blur-[16px] backdrop-saturate-180 shadow-[inset_0_1px_0_rgba(255,255,255,.5),0_16px_34px_-18px_rgba(0,0,0,.7)] transition-[opacity,transform,visibility] duration-250 [text-shadow:none] group-hover:visible group-hover:translate-y-0 group-hover:opacity-100 group-focus-visible:visible group-focus-visible:translate-y-0 group-focus-visible:opacity-100 motion-reduce:transition-[opacity,visibility] after:absolute after:top-full after:left-1/2 after:size-3 after:-translate-x-1/2 after:-translate-y-[5px] after:rotate-45 after:border-r after:border-b after:border-white/40 after:bg-inherit">Auto-renews &middot; cancel anytime up to 24h before</span></span>.
    You've used
    <span tabindex="0" class="group relative cursor-help font-extrabold text-lgt11-accent outline-none border-b-2 border-dotted border-white/50 focus-visible:rounded focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-white">68%<span role="tooltip" class="pointer-events-none invisible absolute bottom-[calc(100%+12px)] left-1/2 z-5 w-max max-w-[220px] -translate-x-1/2 translate-y-1.5 rounded-[14px] border border-white/40 bg-white/16 px-3.25 py-2.25 text-[13px] font-semibold leading-snug text-white opacity-0 backdrop-blur-[16px] backdrop-saturate-180 shadow-[inset_0_1px_0_rgba(255,255,255,.5),0_16px_34px_-18px_rgba(0,0,0,.7)] transition-[opacity,transform,visibility] duration-250 [text-shadow:none] group-hover:visible group-hover:translate-y-0 group-hover:opacity-100 group-focus-visible:visible group-focus-visible:translate-y-0 group-focus-visible:opacity-100 motion-reduce:transition-[opacity,visibility] after:absolute after:top-full after:left-1/2 after:size-3 after:-translate-x-1/2 after:-translate-y-[5px] after:rotate-45 after:border-r after:border-b after:border-white/40 after:bg-inherit">34 GB of your 50 GB quota</span></span>
    of storage this cycle, and
    <span tabindex="0" class="group relative cursor-help font-extrabold text-lgt11-accent outline-none border-b-2 border-dotted border-white/50 focus-visible:rounded focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-white">3 seats<span role="tooltip" class="pointer-events-none invisible absolute bottom-[calc(100%+12px)] left-1/2 z-5 w-max max-w-[220px] -translate-x-1/2 translate-y-1.5 rounded-[14px] border border-white/40 bg-white/16 px-3.25 py-2.25 text-[13px] font-semibold leading-snug text-white opacity-0 backdrop-blur-[16px] backdrop-saturate-180 shadow-[inset_0_1px_0_rgba(255,255,255,.5),0_16px_34px_-18px_rgba(0,0,0,.7)] transition-[opacity,transform,visibility] duration-250 [text-shadow:none] group-hover:visible group-hover:translate-y-0 group-hover:opacity-100 group-focus-visible:visible group-focus-visible:translate-y-0 group-focus-visible:opacity-100 motion-reduce:transition-[opacity,visibility] after:absolute after:top-full after:left-1/2 after:size-3 after:-translate-x-1/2 after:-translate-y-[5px] after:rotate-45 after:border-r after:border-b after:border-white/40 after:bg-inherit">2 active, 1 pending invite</span></span>
    are assigned.
  </p>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-lgt11-accent: #7fd7ea;
  --color-lgt11-accent: oklch(0.85 0.13 200);
  --font-lgt11-sans: 'Manrope', system-ui, sans-serif;
}
```

How this works

Hover is half the interaction. The rule this component exists to demonstrate: type the focus twin immediately after the hover state, every time. It is two extra variants and it is the difference between a tooltip and a mouse-only easter egg.

class="invisible opacity-0 translate-y-1.5
       group-hover:visible group-hover:opacity-100 group-hover:translate-y-0
       group-focus-visible:visible group-focus-visible:opacity-100
       group-focus-visible:translate-y-0"

invisible, not just opacity-0. A transparent element is still in the accessibility tree and still hoverable. visibility:hidden removes it from both, and transitioning visibility with a delay lets the fade finish before it disappears.

The arrow inherits. A 12px square rotated 45 degrees with bg-inherit and two matching borders. Because it inherits the bubble's tint, retinting the tooltip retints the arrow automatically — no second colour to keep in sync.

Frost, don't block. The point of a glass tooltip is that the sentence underneath stays legible; that is why the tint is 16% rather than a solid fill.

Make it yours

  • Flip to a bottom tooltip by swapping bottom-full for top-full and moving the arrow to the top edge.
  • Add delay-300 to the show transition so quick pointer passes across a paragraph do not flicker a row of bubbles.
  • Widen with max-w-[280px] for two-line hints; beyond that you want a popover, not a tooltip.
  • Recolour the frost from the bubble alone — bg-inherit on the arrow follows automatically.
  • For rich, interactive content use the native popover API instead; a tooltip that contains links is a popover wearing the wrong role.

Gotchas — read before shipping

  • A hover-only tooltip is inaccessible. If you take one rule from this collection, make it the group-focus-visible: twin.
  • opacity-0 alone leaves the tooltip hoverable and announceable; pair it with invisible.
  • pointer-events-none matters on a bubble that overlaps its trigger — without it the tooltip can capture the pointer and flicker itself away.
  • Transitioning visibility needs the delay on the way out only. Delaying it on the way in makes the tooltip feel broken.
  • Tooltip text sits over unpredictable page content. Keep it full-opacity white on a tint of at least 16%.
  • Do not put essential information in a tooltip. Glass or not, it is a hint layer, not a content layer.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Utilities only, no JavaScript. Where backdrop-filter is unavailable the tooltip degrades to a solid capsule with identical behaviour and positioning.

Techniques used in this demo

HTML & JSno Tailwind involved

Search CodeFronts

Loading…