Tailwind v4MIT licensed

Tailwind Responsive Glass Sidebar to Bottom Tabs

One glass navigation that adapts to its container: a floating vertical sidebar when there is room, re-flowing into a bottom tab bar when there is not. Same links, same material, no duplicated markup and no JavaScript. The port puts the whole reflow on the elements as @max-[560px]: utilities, which makes the two layouts readable side by side.

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="nbtw-24 w-full min-h-svh p-3.5 font-nb24-sans bg-[linear-gradient(130deg,#654ea3,#4776e6_60%,#8e54e9)]" aria-label="Responsive glass sidebar to bottom tabs demo">
  <div class="@container relative min-h-[calc(100svh-28px)] rounded-[20px] overflow-hidden bg-[radial-gradient(circle_at_30%_20%,rgba(255,255,255,.14),transparent_60%),url('https://picsum.photos/seed/nb24/1000/700')] bg-center bg-cover">
    <nav class="absolute z-[5] top-4 left-4 bottom-4 flex flex-col items-stretch gap-1.5 w-[150px] px-2.5 py-3.5 rounded-[18px] text-white bg-[color-mix(in_oklab,white_14%,transparent)] border border-white/40 shadow-[inset_0_1px_0_rgba(255,255,255,.5),0_20px_44px_-24px_rgba(0,0,0,.6)] backdrop-blur-[24px] backdrop-saturate-[1.8] @max-[560px]:top-auto @max-[560px]:inset-x-4 @max-[560px]:bottom-4 @max-[560px]:w-auto @max-[560px]:flex-row @max-[560px]:justify-around @max-[560px]:p-2" aria-label="Primary">
      <span class="py-1.5 pb-2.5 text-center text-[22px] @max-[560px]:hidden" aria-hidden="true">◆</span>
      <a class="flex items-center gap-3 min-h-11 px-3.5 rounded-xl no-underline text-white/85 text-[14.5px] font-semibold transition-[background-color,color] duration-200 hover:bg-white/[0.16] hover:text-white focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 aria-[current=page]:bg-white/[0.24] aria-[current=page]:text-white @max-[560px]:flex-col @max-[560px]:gap-[3px] @max-[560px]:justify-center @max-[560px]:min-w-14 @max-[560px]:px-1.5 @max-[560px]:py-1.5" href="#nbtw-24" aria-current="page"><span class="w-5.5 text-center text-[19px] leading-none @max-[560px]:w-auto" aria-hidden="true">⌂</span><span class="@max-[560px]:text-[11px]">Home</span></a>
      <a class="flex items-center gap-3 min-h-11 px-3.5 rounded-xl no-underline text-white/85 text-[14.5px] font-semibold transition-[background-color,color] duration-200 hover:bg-white/[0.16] hover:text-white focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 @max-[560px]:flex-col @max-[560px]:gap-[3px] @max-[560px]:justify-center @max-[560px]:min-w-14 @max-[560px]:px-1.5 @max-[560px]:py-1.5" href="#nbtw-24"><span class="w-5.5 text-center text-[19px] leading-none @max-[560px]:w-auto" aria-hidden="true">⌕</span><span class="@max-[560px]:text-[11px]">Search</span></a>
      <a class="flex items-center gap-3 min-h-11 px-3.5 rounded-xl no-underline text-white/85 text-[14.5px] font-semibold transition-[background-color,color] duration-200 hover:bg-white/[0.16] hover:text-white focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 @max-[560px]:flex-col @max-[560px]:gap-[3px] @max-[560px]:justify-center @max-[560px]:min-w-14 @max-[560px]:px-1.5 @max-[560px]:py-1.5" href="#nbtw-24"><span class="w-5.5 text-center text-[19px] leading-none @max-[560px]:w-auto" aria-hidden="true">▤</span><span class="@max-[560px]:text-[11px]">Library</span></a>
      <a class="flex items-center gap-3 min-h-11 px-3.5 rounded-xl no-underline text-white/85 text-[14.5px] font-semibold transition-[background-color,color] duration-200 hover:bg-white/[0.16] hover:text-white focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 @max-[560px]:flex-col @max-[560px]:gap-[3px] @max-[560px]:justify-center @max-[560px]:min-w-14 @max-[560px]:px-1.5 @max-[560px]:py-1.5" href="#nbtw-24"><span class="w-5.5 text-center text-[19px] leading-none @max-[560px]:w-auto" aria-hidden="true">◔</span><span class="@max-[560px]:text-[11px]">Activity</span></a>
      <a class="flex items-center gap-3 min-h-11 px-3.5 rounded-xl no-underline text-white/85 text-[14.5px] font-semibold transition-[background-color,color] duration-200 hover:bg-white/[0.16] hover:text-white focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 @max-[560px]:flex-col @max-[560px]:gap-[3px] @max-[560px]:justify-center @max-[560px]:min-w-14 @max-[560px]:px-1.5 @max-[560px]:py-1.5" href="#nbtw-24"><span class="w-5.5 text-center text-[19px] leading-none @max-[560px]:w-auto" aria-hidden="true">◉</span><span class="@max-[560px]:text-[11px]">Profile</span></a>
    </nav>
    <div class="min-h-[calc(100svh-28px)] grid place-items-center p-6 ps-[190px] @max-[560px]:p-6 @max-[560px]:pb-30">
      <p class="max-w-[34ch] text-center text-white text-[15px] font-semibold leading-[1.6] [text-shadow:0_2px_14px_rgba(0,0,0,.35)]">Resize the preview: the glass sidebar re-flows into a bottom tab bar — one nav, one material, zero duplicate markup, and the whole reflow stated on the elements themselves.</p>
    </div>
  </div>
</section>
@import "tailwindcss";

@theme {
  --font-nb24-sans: system-ui, 'Segoe 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 {
  --font-nb24-sans: system-ui, 'Segoe UI', sans-serif;
}

What changed in the port

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

  • Both layouts live in one class list, which is the readability argument for container-query variants: you can see the sidebar and the tab bar described side by side.
  • The query is against the app shell's inline size, not the viewport, so the nav reflows correctly inside a split pane or an embedded preview — the cases a media query gets wrong.
  • Only layout properties change. The glass recipe is written once and shared by both forms, which is what keeps them reading as one component.
  • There is exactly one copy of the links. No mobile duplicate to drift, and no second set of accessible names to maintain.
  • 44px targets are preserved in both directions — min-h-11 for the sidebar rows, min-w-14 for the bottom tabs.
  • The main region flips its own padding under the same variant, because content hiding behind a bottom bar is the classic bug in this pattern.
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 Responsive Glass Sidebar to Bottom Tabs
Source: https://codefronts.com/navigation/tailwind-liquid-glass-navbars/tailwind-responsive-glass-sidebar-to-bottom-tabs/

One glass navigation that adapts to its container: a floating vertical sidebar when there is room, re-flowing into a bottom tab bar when there is not. Same links, same material, no duplicated markup and no JavaScript. The port puts the whole reflow on the elements as @max-[560px]: utilities, which makes the two layouts readable side by side.
## HTML
```html
<section class="nbtw-24 w-full min-h-svh p-3.5 font-nb24-sans bg-[linear-gradient(130deg,#654ea3,#4776e6_60%,#8e54e9)]" aria-label="Responsive glass sidebar to bottom tabs demo">
  <div class="@container relative min-h-[calc(100svh-28px)] rounded-[20px] overflow-hidden bg-[radial-gradient(circle_at_30%_20%,rgba(255,255,255,.14),transparent_60%),url('https://picsum.photos/seed/nb24/1000/700')] bg-center bg-cover">
    <nav class="absolute z-[5] top-4 left-4 bottom-4 flex flex-col items-stretch gap-1.5 w-[150px] px-2.5 py-3.5 rounded-[18px] text-white bg-[color-mix(in_oklab,white_14%,transparent)] border border-white/40 shadow-[inset_0_1px_0_rgba(255,255,255,.5),0_20px_44px_-24px_rgba(0,0,0,.6)] backdrop-blur-[24px] backdrop-saturate-[1.8] @max-[560px]:top-auto @max-[560px]:inset-x-4 @max-[560px]:bottom-4 @max-[560px]:w-auto @max-[560px]:flex-row @max-[560px]:justify-around @max-[560px]:p-2" aria-label="Primary">
      <span class="py-1.5 pb-2.5 text-center text-[22px] @max-[560px]:hidden" aria-hidden="true">◆</span>
      <a class="flex items-center gap-3 min-h-11 px-3.5 rounded-xl no-underline text-white/85 text-[14.5px] font-semibold transition-[background-color,color] duration-200 hover:bg-white/[0.16] hover:text-white focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 aria-[current=page]:bg-white/[0.24] aria-[current=page]:text-white @max-[560px]:flex-col @max-[560px]:gap-[3px] @max-[560px]:justify-center @max-[560px]:min-w-14 @max-[560px]:px-1.5 @max-[560px]:py-1.5" href="#nbtw-24" aria-current="page"><span class="w-5.5 text-center text-[19px] leading-none @max-[560px]:w-auto" aria-hidden="true">⌂</span><span class="@max-[560px]:text-[11px]">Home</span></a>
      <a class="flex items-center gap-3 min-h-11 px-3.5 rounded-xl no-underline text-white/85 text-[14.5px] font-semibold transition-[background-color,color] duration-200 hover:bg-white/[0.16] hover:text-white focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 @max-[560px]:flex-col @max-[560px]:gap-[3px] @max-[560px]:justify-center @max-[560px]:min-w-14 @max-[560px]:px-1.5 @max-[560px]:py-1.5" href="#nbtw-24"><span class="w-5.5 text-center text-[19px] leading-none @max-[560px]:w-auto" aria-hidden="true">⌕</span><span class="@max-[560px]:text-[11px]">Search</span></a>
      <a class="flex items-center gap-3 min-h-11 px-3.5 rounded-xl no-underline text-white/85 text-[14.5px] font-semibold transition-[background-color,color] duration-200 hover:bg-white/[0.16] hover:text-white focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 @max-[560px]:flex-col @max-[560px]:gap-[3px] @max-[560px]:justify-center @max-[560px]:min-w-14 @max-[560px]:px-1.5 @max-[560px]:py-1.5" href="#nbtw-24"><span class="w-5.5 text-center text-[19px] leading-none @max-[560px]:w-auto" aria-hidden="true">▤</span><span class="@max-[560px]:text-[11px]">Library</span></a>
      <a class="flex items-center gap-3 min-h-11 px-3.5 rounded-xl no-underline text-white/85 text-[14.5px] font-semibold transition-[background-color,color] duration-200 hover:bg-white/[0.16] hover:text-white focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 @max-[560px]:flex-col @max-[560px]:gap-[3px] @max-[560px]:justify-center @max-[560px]:min-w-14 @max-[560px]:px-1.5 @max-[560px]:py-1.5" href="#nbtw-24"><span class="w-5.5 text-center text-[19px] leading-none @max-[560px]:w-auto" aria-hidden="true">◔</span><span class="@max-[560px]:text-[11px]">Activity</span></a>
      <a class="flex items-center gap-3 min-h-11 px-3.5 rounded-xl no-underline text-white/85 text-[14.5px] font-semibold transition-[background-color,color] duration-200 hover:bg-white/[0.16] hover:text-white focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 @max-[560px]:flex-col @max-[560px]:gap-[3px] @max-[560px]:justify-center @max-[560px]:min-w-14 @max-[560px]:px-1.5 @max-[560px]:py-1.5" href="#nbtw-24"><span class="w-5.5 text-center text-[19px] leading-none @max-[560px]:w-auto" aria-hidden="true">◉</span><span class="@max-[560px]:text-[11px]">Profile</span></a>
    </nav>
    <div class="min-h-[calc(100svh-28px)] grid place-items-center p-6 ps-[190px] @max-[560px]:p-6 @max-[560px]:pb-30">
      <p class="max-w-[34ch] text-center text-white text-[15px] font-semibold leading-[1.6] [text-shadow:0_2px_14px_rgba(0,0,0,.35)]">Resize the preview: the glass sidebar re-flows into a bottom tab bar — one nav, one material, zero duplicate markup, and the whole reflow stated on the elements themselves.</p>
    </div>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --font-nb24-sans: system-ui, 'Segoe UI', sans-serif;
}
```

How this works

The nav is one element with two layouts. Both are legible in the same class list, which is the readability argument for container-query variants in one sentence:

class="absolute top-4 left-4 bottom-4 w-[150px] flex flex-col
       @max-[560px]:top-auto @max-[560px]:inset-x-4 @max-[560px]:bottom-4
       @max-[560px]:w-auto @max-[560px]:flex-row @max-[560px]:justify-around"

Container, not viewport. The query is against the app shell's inline size, so this nav reflows correctly in a split pane, an embedded preview, or a dashboard column — every place a viewport media query gets the answer wrong.

Only layout changes. The fill, rim, shadow and blur are written once and inherited by both forms. That is what keeps the two states looking like one component at two shapes rather than two designs.

One source of truth for the links. There is no mobile copy of the navigation to fall out of sync — the single most valuable property of this pattern, and the reason it is worth the slightly denser class lists.

Make it yours

  • Change the breakpoint by editing @max-[560px] on the four elements that use it, or move to a named container size if it matches your scale.
  • Hide labels entirely in the bottom bar with @max-[560px]:hidden on the label span — keep the aria-labels if you do.
  • Anchor the sidebar to the right with right-4 left-auto, or detach it further with a larger inset for a more floating look.
  • Add a second breakpoint (@max-[380px]:) to drop to icons only on the narrowest containers.
  • Swap the container query for a media query if the nav is always at viewport scale; the utility names barely change.

Gotchas — read before shipping

  • Container query variants need an ancestor with @container. Without it every @max-[560px]: utility compiles and silently never matches.
  • The container must be a sized ancestor of the nav, not the nav itself — an element cannot query its own inline size.
  • Keep 44px targets in both orientations. It is easy to satisfy the vertical form and end up with 32px-tall bottom tabs.
  • Never duplicate the links for mobile. Two copies of a navigation is how the two versions drift, and it doubles the accessible-name maintenance.
  • The main region needs its padding flipped too (@max-[560px]:p-6), or content hides behind the bottom bar.
  • Container queries create a containment context, which can affect how absolutely-positioned descendants resolve. Check any overlay inside the shell after adding one.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Tailwind v4 sets the floor, and container queries (Chrome 105+, Safari 16+, Firefox 110+) are inside it. Where they are unavailable the nav keeps its sidebar layout, which remains fully usable.

Techniques used in this demo

HTML & JSno Tailwind involved

Search CodeFronts

Loading…