Tailwind v4MIT licensed

Tailwind Liquid Glass Dropdown Menu

A dropdown that snaps in like a liquid drop, built on native <details> so open/close, keyboard toggling and focus are free. The port's clean move is group on the <details> element itself: group-open: rotates the chevron and runs the panel's spring, and there is no state anywhere else.

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-09 relative flex w-full min-h-svh items-start justify-center overflow-hidden px-5 py-30 font-lgt09-sans [background:radial-gradient(circle_at_20%_30%,#4a2f8a,transparent_55%),radial-gradient(circle_at_80%_20%,#1e5aa8,transparent_50%),radial-gradient(circle_at_50%_90%,#a83d7a,transparent_50%),#0a0620]" aria-label="Tailwind liquid glass dropdown menu">
  <div aria-hidden="true" class="pointer-events-none absolute -inset-10 opacity-70 blur-[60px] [background:radial-gradient(circle_at_30%_40%,#7c3aed,transparent_45%),radial-gradient(circle_at_70%_60%,#0891b2,transparent_45%),radial-gradient(circle_at_50%_80%,#db2777,transparent_40%)]"></div>

  <details class="group relative z-2 w-[min(240px,80vw)]">
    <summary class="flex cursor-pointer list-none items-center justify-between rounded-[14px] border border-white/35 bg-white/14 px-4.5 py-3.25 text-[15px] font-bold text-white backdrop-blur-[16px] backdrop-saturate-170 shadow-[inset_0_1px_0_rgba(255,255,255,.5),0_12px_26px_-16px_rgba(0,0,0,.6)] transition-colors duration-200 hover:bg-white/20 focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-white [&amp;::-webkit-details-marker]:hidden">
      Workspace
      <span aria-hidden="true" class="transition-transform duration-300 group-open:rotate-180 motion-reduce:transition-none">&#9662;</span>
    </summary>

    <div role="menu" class="absolute inset-x-0 mt-2.5 origin-top rounded-[16px] border border-white/30 bg-white/12 p-2 backdrop-blur-[22px] backdrop-saturate-180 shadow-[inset_0_1px_0_rgba(255,255,255,.4),0_26px_50px_-24px_rgba(0,0,0,.7)] group-open:animate-lgt09-drop motion-reduce:group-open:animate-none">
      <a role="menuitem" href="#lgt-09" class="block rounded-[10px] px-3.5 py-2.75 text-sm font-semibold text-white no-underline transition-colors duration-200 hover:bg-white/18 focus-visible:bg-white/18 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-white">Projects</a>
      <a role="menuitem" href="#lgt-09" class="block rounded-[10px] px-3.5 py-2.75 text-sm font-semibold text-white no-underline transition-colors duration-200 hover:bg-white/18 focus-visible:bg-white/18 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-white">Team</a>
      <a role="menuitem" href="#lgt-09" class="block rounded-[10px] px-3.5 py-2.75 text-sm font-semibold text-white no-underline transition-colors duration-200 hover:bg-white/18 focus-visible:bg-white/18 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-white">Settings</a>
      <hr class="mx-2 my-1.5 border-0 border-t border-white/18">
      <a role="menuitem" href="#lgt-09" class="block rounded-[10px] px-3.5 py-2.75 text-sm font-semibold text-white no-underline transition-colors duration-200 hover:bg-white/18 focus-visible:bg-white/18 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-white">Sign out</a>
    </div>
  </details>
</section>
@import "tailwindcss";

@theme {
  --font-lgt09-sans: 'Manrope', system-ui, sans-serif;
  --animate-lgt09-drop: lgt-09-drop 0.4s cubic-bezier(0.3, 1.3, 0.5, 1);
}

@keyframes lgt-09-drop {
  0% {
    opacity: 0;
    transform: translateY(-10px) scaleY(0.6);
  }

  60% {
    opacity: 1;
    transform: translateY(2px) scaleY(1.05);
  }

  100% {
    opacity: 1;
    transform: translateY(0) scaleY(1);
  }
}

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 {
  --font-lgt09-sans: 'Manrope', system-ui, sans-serif;
  --animate-lgt09-drop: lgt-09-drop 0.4s cubic-bezier(0.3, 1.3, 0.5, 1);
}

@keyframes lgt-09-drop {
  0% {
    opacity: 0;
    transform: translateY(-10px) scaleY(0.6);
  }

  60% {
    opacity: 1;
    transform: translateY(2px) scaleY(1.05);
  }

  100% {
    opacity: 1;
    transform: translateY(0) scaleY(1);
  }
}
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.

  • group on the <details> turns the native [open] attribute into a variant, so the chevron and the panel both read one state with no JavaScript.
  • [&::-webkit-details-marker]:hidden is the arbitrary-variant form of a vendor pseudo-element rule — one of the few places a raw selector is still required.
  • The spring is an --animate-* theme entry; origin-top is what makes the overshoot read as a landing.
  • Blurred blobs behind the trigger exist so the frost has colour to sample — staging is part of the material.
  • Menu rows are real anchors with menu roles; the glass is styling, not a substitute for semantics.
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 Dropdown Menu
Source: https://codefronts.com/design-styles/tailwind-liquid-glass-effects/tailwind-liquid-glass-dropdown-menu/

A dropdown that snaps in like a liquid drop, built on native <details> so open/close, keyboard toggling and focus are free. The port's clean move is group on the <details> element itself: group-open: rotates the chevron and runs the panel's spring, and there is no state anywhere else.
## HTML
```html
<section class="lgt-09 relative flex w-full min-h-svh items-start justify-center overflow-hidden px-5 py-30 font-lgt09-sans [background:radial-gradient(circle_at_20%_30%,#4a2f8a,transparent_55%),radial-gradient(circle_at_80%_20%,#1e5aa8,transparent_50%),radial-gradient(circle_at_50%_90%,#a83d7a,transparent_50%),#0a0620]" aria-label="Tailwind liquid glass dropdown menu">
  <div aria-hidden="true" class="pointer-events-none absolute -inset-10 opacity-70 blur-[60px] [background:radial-gradient(circle_at_30%_40%,#7c3aed,transparent_45%),radial-gradient(circle_at_70%_60%,#0891b2,transparent_45%),radial-gradient(circle_at_50%_80%,#db2777,transparent_40%)]"></div>

  <details class="group relative z-2 w-[min(240px,80vw)]">
    <summary class="flex cursor-pointer list-none items-center justify-between rounded-[14px] border border-white/35 bg-white/14 px-4.5 py-3.25 text-[15px] font-bold text-white backdrop-blur-[16px] backdrop-saturate-170 shadow-[inset_0_1px_0_rgba(255,255,255,.5),0_12px_26px_-16px_rgba(0,0,0,.6)] transition-colors duration-200 hover:bg-white/20 focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-white [&amp;::-webkit-details-marker]:hidden">
      Workspace
      <span aria-hidden="true" class="transition-transform duration-300 group-open:rotate-180 motion-reduce:transition-none">&#9662;</span>
    </summary>

    <div role="menu" class="absolute inset-x-0 mt-2.5 origin-top rounded-[16px] border border-white/30 bg-white/12 p-2 backdrop-blur-[22px] backdrop-saturate-180 shadow-[inset_0_1px_0_rgba(255,255,255,.4),0_26px_50px_-24px_rgba(0,0,0,.7)] group-open:animate-lgt09-drop motion-reduce:group-open:animate-none">
      <a role="menuitem" href="#lgt-09" class="block rounded-[10px] px-3.5 py-2.75 text-sm font-semibold text-white no-underline transition-colors duration-200 hover:bg-white/18 focus-visible:bg-white/18 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-white">Projects</a>
      <a role="menuitem" href="#lgt-09" class="block rounded-[10px] px-3.5 py-2.75 text-sm font-semibold text-white no-underline transition-colors duration-200 hover:bg-white/18 focus-visible:bg-white/18 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-white">Team</a>
      <a role="menuitem" href="#lgt-09" class="block rounded-[10px] px-3.5 py-2.75 text-sm font-semibold text-white no-underline transition-colors duration-200 hover:bg-white/18 focus-visible:bg-white/18 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-white">Settings</a>
      <hr class="mx-2 my-1.5 border-0 border-t border-white/18">
      <a role="menuitem" href="#lgt-09" class="block rounded-[10px] px-3.5 py-2.75 text-sm font-semibold text-white no-underline transition-colors duration-200 hover:bg-white/18 focus-visible:bg-white/18 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-white">Sign out</a>
    </div>
  </details>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --font-lgt09-sans: 'Manrope', system-ui, sans-serif;
  --animate-lgt09-drop: lgt-09-drop 0.4s cubic-bezier(0.3, 1.3, 0.5, 1);
}

@keyframes lgt-09-drop {
  0% {
    opacity: 0;
    transform: translateY(-10px) scaleY(0.6);
  }

  60% {
    opacity: 1;
    transform: translateY(2px) scaleY(1.05);
  }

  100% {
    opacity: 1;
    transform: translateY(0) scaleY(1);
  }
}
```

How this works

<details> is the whole component. Open state, keyboard toggling, focus behaviour and the disclosure semantics all come from the element. The port adds group to it, which turns the native [open] attribute into a variant that any descendant can read:

<details class="group relative">
  <summary class="list-none [&::-webkit-details-marker]:hidden">
    Workspace <span class="transition-transform group-open:rotate-180">▾</span>
  </summary>
  <div class="group-open:animate-lgt09-drop origin-top ...">

The spring is a keyframe with an overshoot, not a bounce library: 0% squashed to scaleY(.6) and lifted 10px, 60% overshooting to 1.05, 100% settled. Combined with origin-top it reads as a drop of liquid landing and settling.

The background matters. Blurred gradient blobs sit behind the trigger specifically so the panel's backdrop-blur-[22px] has colour to sample. A frosted panel over flat navy looks identical to a solid panel — the demo has to earn its material.

Make it yours

  • Change the landing feel in the @keyframes overshoot — drop the 1.05 step for a strictly professional open with no bounce.
  • Right-align the panel by swapping left-0 right-0 for right-0 w-56.
  • Restyle rows entirely inside the item class string; hover:bg-white/18 is the only state they need.
  • Make it a real menu button with aria-haspopup and roving tabindex if it drives navigation rather than links.
  • Widen or narrow with the single w-[min(240px,80vw)] on the details element.

Gotchas — read before shipping

  • Put the animation on the panel, not the summary. Animating the trigger makes the click target move under the pointer mid-press.
  • list-none alone does not remove the marker in WebKit — you also need [&::-webkit-details-marker]:hidden.
  • Removing the marker means you owe the user another open/close cue; the rotating chevron is that cue, not decoration.
  • group-open: only exists because group is on the <details>. On the summary it silently matches nothing.
  • The panel must sit over non-flat content or the frost is invisible — this is a demo-staging problem that becomes a real one in flat dashboards.
  • <details> does not close on outside click. If that matters, add a tiny listener; do not rebuild the disclosure in JS to get it.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

details/summary is universal and needs no polyfill; Tailwind v4's sheet sets the floor. Where backdrop-filter is unavailable the panel is a solid frosted-tint card and behaves identically.

Techniques used in this demo

Plain CSSno Tailwind surface

HTML & JSno Tailwind involved

Search CodeFronts

Loading…