30 Tailwind CSS Grid Layouts
02 / 30

All 30 in 30 Tailwind CSS Grid Layouts

  1. 01Tailwind Full-Bleed Article Layout for Long-Form Editorial
  2. 02Tailwind Docs Layout with Sticky Table of Contents
  3. 03Tailwind Photo Gallery Grid with auto-fill and Real Images
  4. 04Tailwind Holy Grail Page Layout for a News Site
  5. 05Tailwind Data Table with Subgrid Rows and Status Pills
  6. 06Tailwind Overlapping Card Hero for a Case Study
  7. 07Tailwind Help Center Layout with Fixed Sidebars
  8. 08Tailwind 12 Column Grid System for Marketing Pages
  9. 09Tailwind Bento Grid for a Product Feature Section
  10. 10Tailwind Magazine Spread Layout with Overlapping Headline
  11. 11Tailwind Responsive Card Grid for an Integrations Directory
  12. 12Tailwind CMS Category Grid that Compacts Itself with has()
  13. 13Tailwind Masonry Layout for a Saved Ideas Board
  14. 14Tailwind Hexagon Team Grid with clip-path Avatars
  15. 15Tailwind Subgrid Cards with Perfectly Aligned Buttons
  16. 16Tailwind Analytics Dashboard Layout with Grid App Shell
  17. 17Tailwind Pricing Table with Subgrid and a Featured Plan
  18. 18Tailwind Kanban Board with Scroll Snap Columns
  19. 19Tailwind Video Thumbnail Grid with Zero Layout Shift
  20. 20Tailwind Container Query Card for Reusable Article Teasers
  21. 21Tailwind Diagonal Section Band with skewY Counter-Skew
  22. 22Tailwind Asymmetric Poster Hero with Layered Grid Regions
  23. 23Tailwind Mosaic Photo Wall with a Designed Span Sequence
  24. 24Tailwind Dense Grid Packing for a Mixed-Size Asset Library
  25. 25Tailwind Onboarding Stepper with CSS Counters
  26. 26Tailwind macOS Window Layout with Vibrancy Sidebar
  27. 27Tailwind Scroll Snap Carousel with Peeking Slides
  28. 28Tailwind Status Map UI with Grid Coordinate Pins
  29. 29Tailwind Logo Wall with 1px Gap Hairline Dividers
  30. 30Tailwind Periodic Table Layout with Grid Coordinates
Pure TailwindMIT licensed

Tailwind Docs Layout with Sticky Table of Contents

A real API reference page: version pill, on-this-page rail that tracks the reader, code samples that scroll instead of shoving the layout around. One missing declaration kills position: sticky in grid — here the cure sits two utilities from the cause.

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="tgx-02 w-full min-h-svh bg-tgx02-bg text-tgx02-ink font-tgx02-sans p-5">
  <div class="grid grid-cols-[minmax(200px,240px)_minmax(0,1fr)] max-sm:grid-cols-1 gap-6 h-[420px] overflow-y-auto overscroll-contain rounded-2xl border border-tgx02-edge bg-tgx02-panel p-5">
    <aside>
      <nav aria-label="On this page" class="sticky top-0 self-start max-sm:static flex flex-col gap-0.5 rounded-xl border border-tgx02-edge bg-tgx02-nav p-3">
        <div class="flex items-center justify-between gap-2 px-1 pb-2 mb-1 border-b border-tgx02-edge">
          <p class="text-[0.66rem] tracking-[0.14em] uppercase text-tgx02-dim">On this page</p>
          <span class="font-tgx02-mono text-[0.6rem] px-1.5 py-0.5 rounded bg-tgx02-limetint text-tgx02-lime">v3.2</span>
        </div>
        <a href="#tgx02-auth" aria-current="location" class="text-[0.84rem] no-underline rounded-lg px-2.5 min-h-9 flex items-center border-l-2 border-transparent text-tgx02-dim transition-colors hover:text-tgx02-ink hover:bg-tgx02-hover aria-[current=location]:text-tgx02-lime aria-[current=location]:border-l-tgx02-lime aria-[current=location]:bg-tgx02-limetint focus-visible:outline-2 focus-visible:outline-tgx02-lime focus-visible:outline-offset-2">Authentication</a>
        <a href="#tgx02-list" class="text-[0.84rem] no-underline rounded-lg px-2.5 min-h-9 flex items-center border-l-2 border-transparent text-tgx02-dim transition-colors hover:text-tgx02-ink hover:bg-tgx02-hover focus-visible:outline-2 focus-visible:outline-tgx02-lime focus-visible:outline-offset-2">List shipments</a>
        <a href="#tgx02-rate" class="text-[0.84rem] no-underline rounded-lg px-2.5 min-h-9 flex items-center border-l-2 border-transparent text-tgx02-dim transition-colors hover:text-tgx02-ink hover:bg-tgx02-hover focus-visible:outline-2 focus-visible:outline-tgx02-lime focus-visible:outline-offset-2">Rate limits</a>
        <a href="#tgx02-errors" class="text-[0.84rem] no-underline rounded-lg px-2.5 min-h-9 flex items-center border-l-2 border-transparent text-tgx02-dim transition-colors hover:text-tgx02-ink hover:bg-tgx02-hover focus-visible:outline-2 focus-visible:outline-tgx02-lime focus-visible:outline-offset-2">Error codes</a>
        <a href="#tgx02-webhooks" class="text-[0.84rem] no-underline rounded-lg px-2.5 min-h-9 flex items-center border-l-2 border-transparent text-tgx02-dim transition-colors hover:text-tgx02-ink hover:bg-tgx02-hover focus-visible:outline-2 focus-visible:outline-tgx02-lime focus-visible:outline-offset-2">Webhooks</a>
      </nav>
    </aside>
    <main class="flex flex-col gap-7 min-w-0">
      <header class="flex flex-col gap-2">
        <p class="font-tgx02-mono text-[0.68rem] text-tgx02-dim">Northwind Freight API</p>
        <h2 class="text-[1.35rem] font-semibold tracking-[-0.01em]">Shipments</h2>
        <p class="text-[0.88rem] leading-[1.65] text-tgx02-dim">Create, track and reconcile shipments. All endpoints are versioned and return JSON.</p>
      </header>
      <article id="tgx02-auth" class="scroll-mt-4 flex flex-col gap-2">
        <h3 class="text-[1rem] font-semibold text-tgx02-lime">Authentication</h3>
        <p class="text-[0.86rem] leading-[1.65] text-tgx02-dim">Send your secret key as a bearer token. Keys are environment-scoped; a test key never touches a live manifest.</p>
        <pre class="font-tgx02-mono text-[0.76rem] leading-[1.6] text-tgx02-code bg-tgx02-codebg border border-tgx02-edge rounded-lg p-3 overflow-x-auto"><code>curl https://api.northwind.dev/v3/shipments \
  -H "Authorization: Bearer nw_live_8fK2..." \
  -H "Northwind-Version: 2026-07-01"</code></pre>
      </article>
      <article id="tgx02-list" class="scroll-mt-4 flex flex-col gap-2">
        <h3 class="text-[1rem] font-semibold text-tgx02-lime">List shipments</h3>
        <p class="text-[0.86rem] leading-[1.65] text-tgx02-dim">Returns a cursor-paginated list, newest first. The content track is <code class="font-tgx02-mono text-tgx02-ink">minmax(0,1fr)</code>, so the sample above scrolls sideways instead of widening the page.</p>
      </article>
      <article id="tgx02-rate" class="scroll-mt-4 flex flex-col gap-2">
        <h3 class="text-[1rem] font-semibold text-tgx02-lime">Rate limits</h3>
        <p class="text-[0.86rem] leading-[1.65] text-tgx02-dim">1,000 requests per minute per key. Bursts are smoothed over ten seconds; exceeding the window returns <code class="font-tgx02-mono text-tgx02-ink">429</code> with a retry hint.</p>
      </article>
      <article id="tgx02-errors" class="scroll-mt-4 flex flex-col gap-2">
        <h3 class="text-[1rem] font-semibold text-tgx02-lime">Error codes</h3>
        <p class="text-[0.86rem] leading-[1.65] text-tgx02-dim">Every error carries a stable <code class="font-tgx02-mono text-tgx02-ink">type</code>, a human message, and the request id to quote at support.</p>
      </article>
      <article id="tgx02-webhooks" class="scroll-mt-4 flex flex-col gap-2">
        <h3 class="text-[1rem] font-semibold text-tgx02-lime">Webhooks</h3>
        <p class="text-[0.86rem] leading-[1.65] text-tgx02-dim">Subscribe to <code class="font-tgx02-mono text-tgx02-ink">shipment.delivered</code> and friends. Deliveries retry for 24 hours with exponential backoff.</p>
      </article>
    </main>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-tgx02-bg: #1b1d26;
  --color-tgx02-bg: oklch(0.2 0.02 265);
  --color-tgx02-panel: #21242f;
  --color-tgx02-panel: oklch(0.24 0.025 265);
  --color-tgx02-nav: #272b38;
  --color-tgx02-nav: oklch(0.28 0.03 265);
  --color-tgx02-hover: #2e3242;
  --color-tgx02-hover: oklch(0.32 0.03 265);
  --color-tgx02-codebg: #171923;
  --color-tgx02-codebg: oklch(0.18 0.02 265);
  --color-tgx02-code: #cfe3a8;
  --color-tgx02-code: oklch(0.88 0.08 125);
  --color-tgx02-edge: #363a4a;
  --color-tgx02-edge: oklch(0.36 0.03 265);
  --color-tgx02-ink: #e9eaf0;
  --color-tgx02-ink: oklch(0.93 0.01 260);
  --color-tgx02-dim: #a7abbb;
  --color-tgx02-dim: oklch(0.73 0.02 260);
  --color-tgx02-lime: #b6e84f;
  --color-tgx02-lime: oklch(0.85 0.19 130);
  --color-tgx02-limetint: #2c3826;
  --color-tgx02-limetint: oklch(0.32 0.05 130);
  --font-tgx02-sans: 'Inter Tight', system-ui, sans-serif;
  --font-tgx02-mono: 'JetBrains Mono', ui-monospace, monospace;
}

.tgx-02 {
  width: 100%;
  min-height: 100svh;
}

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-tgx02-bg: #1b1d26;
  --color-tgx02-bg: oklch(0.2 0.02 265);
  --color-tgx02-panel: #21242f;
  --color-tgx02-panel: oklch(0.24 0.025 265);
  --color-tgx02-nav: #272b38;
  --color-tgx02-nav: oklch(0.28 0.03 265);
  --color-tgx02-hover: #2e3242;
  --color-tgx02-hover: oklch(0.32 0.03 265);
  --color-tgx02-codebg: #171923;
  --color-tgx02-codebg: oklch(0.18 0.02 265);
  --color-tgx02-code: #cfe3a8;
  --color-tgx02-code: oklch(0.88 0.08 125);
  --color-tgx02-edge: #363a4a;
  --color-tgx02-edge: oklch(0.36 0.03 265);
  --color-tgx02-ink: #e9eaf0;
  --color-tgx02-ink: oklch(0.93 0.01 260);
  --color-tgx02-dim: #a7abbb;
  --color-tgx02-dim: oklch(0.73 0.02 260);
  --color-tgx02-lime: #b6e84f;
  --color-tgx02-lime: oklch(0.85 0.19 130);
  --color-tgx02-limetint: #2c3826;
  --color-tgx02-limetint: oklch(0.32 0.05 130);
  --font-tgx02-sans: 'Inter Tight', system-ui, sans-serif;
  --font-tgx02-mono: 'JetBrains Mono', ui-monospace, monospace;
}

.tgx-02 {
  width: 100%;
  min-height: 100svh;
}
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=Inter+Tight:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap">

What changed in the port

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

  • The demo now contains the thing that breaks the layout: a curl sample wider than its column. That is the honest way to show why minmax(0,1fr) is not optional.
  • aria-current="location" is the correct value for a within-page TOC (page belongs on site nav pointing at the current page).
  • Product upgrade: generic 'Getting started / Why sticky breaks' headings became a real versioned API reference with a code block, a version pill and rate-limit copy — the context in which anyone actually builds this layout.
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 Docs Layout with Sticky Table of Contents
Source: https://codefronts.com/layouts/tailwind-css-grid-layouts/tailwind-docs-layout-sticky-table-of-contents/

A real API reference page: version pill, on-this-page rail that tracks the reader, code samples that scroll instead of shoving the layout around. One missing declaration kills position: sticky in grid — here the cure sits two utilities from the cause.
## HTML
```html
<section class="tgx-02 w-full min-h-svh bg-tgx02-bg text-tgx02-ink font-tgx02-sans p-5">
  <div class="grid grid-cols-[minmax(200px,240px)_minmax(0,1fr)] max-sm:grid-cols-1 gap-6 h-[420px] overflow-y-auto overscroll-contain rounded-2xl border border-tgx02-edge bg-tgx02-panel p-5">
    <aside>
      <nav aria-label="On this page" class="sticky top-0 self-start max-sm:static flex flex-col gap-0.5 rounded-xl border border-tgx02-edge bg-tgx02-nav p-3">
        <div class="flex items-center justify-between gap-2 px-1 pb-2 mb-1 border-b border-tgx02-edge">
          <p class="text-[0.66rem] tracking-[0.14em] uppercase text-tgx02-dim">On this page</p>
          <span class="font-tgx02-mono text-[0.6rem] px-1.5 py-0.5 rounded bg-tgx02-limetint text-tgx02-lime">v3.2</span>
        </div>
        <a href="#tgx02-auth" aria-current="location" class="text-[0.84rem] no-underline rounded-lg px-2.5 min-h-9 flex items-center border-l-2 border-transparent text-tgx02-dim transition-colors hover:text-tgx02-ink hover:bg-tgx02-hover aria-[current=location]:text-tgx02-lime aria-[current=location]:border-l-tgx02-lime aria-[current=location]:bg-tgx02-limetint focus-visible:outline-2 focus-visible:outline-tgx02-lime focus-visible:outline-offset-2">Authentication</a>
        <a href="#tgx02-list" class="text-[0.84rem] no-underline rounded-lg px-2.5 min-h-9 flex items-center border-l-2 border-transparent text-tgx02-dim transition-colors hover:text-tgx02-ink hover:bg-tgx02-hover focus-visible:outline-2 focus-visible:outline-tgx02-lime focus-visible:outline-offset-2">List shipments</a>
        <a href="#tgx02-rate" class="text-[0.84rem] no-underline rounded-lg px-2.5 min-h-9 flex items-center border-l-2 border-transparent text-tgx02-dim transition-colors hover:text-tgx02-ink hover:bg-tgx02-hover focus-visible:outline-2 focus-visible:outline-tgx02-lime focus-visible:outline-offset-2">Rate limits</a>
        <a href="#tgx02-errors" class="text-[0.84rem] no-underline rounded-lg px-2.5 min-h-9 flex items-center border-l-2 border-transparent text-tgx02-dim transition-colors hover:text-tgx02-ink hover:bg-tgx02-hover focus-visible:outline-2 focus-visible:outline-tgx02-lime focus-visible:outline-offset-2">Error codes</a>
        <a href="#tgx02-webhooks" class="text-[0.84rem] no-underline rounded-lg px-2.5 min-h-9 flex items-center border-l-2 border-transparent text-tgx02-dim transition-colors hover:text-tgx02-ink hover:bg-tgx02-hover focus-visible:outline-2 focus-visible:outline-tgx02-lime focus-visible:outline-offset-2">Webhooks</a>
      </nav>
    </aside>
    <main class="flex flex-col gap-7 min-w-0">
      <header class="flex flex-col gap-2">
        <p class="font-tgx02-mono text-[0.68rem] text-tgx02-dim">Northwind Freight API</p>
        <h2 class="text-[1.35rem] font-semibold tracking-[-0.01em]">Shipments</h2>
        <p class="text-[0.88rem] leading-[1.65] text-tgx02-dim">Create, track and reconcile shipments. All endpoints are versioned and return JSON.</p>
      </header>
      <article id="tgx02-auth" class="scroll-mt-4 flex flex-col gap-2">
        <h3 class="text-[1rem] font-semibold text-tgx02-lime">Authentication</h3>
        <p class="text-[0.86rem] leading-[1.65] text-tgx02-dim">Send your secret key as a bearer token. Keys are environment-scoped; a test key never touches a live manifest.</p>
        <pre class="font-tgx02-mono text-[0.76rem] leading-[1.6] text-tgx02-code bg-tgx02-codebg border border-tgx02-edge rounded-lg p-3 overflow-x-auto"><code>curl https://api.northwind.dev/v3/shipments \
  -H "Authorization: Bearer nw_live_8fK2..." \
  -H "Northwind-Version: 2026-07-01"</code></pre>
      </article>
      <article id="tgx02-list" class="scroll-mt-4 flex flex-col gap-2">
        <h3 class="text-[1rem] font-semibold text-tgx02-lime">List shipments</h3>
        <p class="text-[0.86rem] leading-[1.65] text-tgx02-dim">Returns a cursor-paginated list, newest first. The content track is <code class="font-tgx02-mono text-tgx02-ink">minmax(0,1fr)</code>, so the sample above scrolls sideways instead of widening the page.</p>
      </article>
      <article id="tgx02-rate" class="scroll-mt-4 flex flex-col gap-2">
        <h3 class="text-[1rem] font-semibold text-tgx02-lime">Rate limits</h3>
        <p class="text-[0.86rem] leading-[1.65] text-tgx02-dim">1,000 requests per minute per key. Bursts are smoothed over ten seconds; exceeding the window returns <code class="font-tgx02-mono text-tgx02-ink">429</code> with a retry hint.</p>
      </article>
      <article id="tgx02-errors" class="scroll-mt-4 flex flex-col gap-2">
        <h3 class="text-[1rem] font-semibold text-tgx02-lime">Error codes</h3>
        <p class="text-[0.86rem] leading-[1.65] text-tgx02-dim">Every error carries a stable <code class="font-tgx02-mono text-tgx02-ink">type</code>, a human message, and the request id to quote at support.</p>
      </article>
      <article id="tgx02-webhooks" class="scroll-mt-4 flex flex-col gap-2">
        <h3 class="text-[1rem] font-semibold text-tgx02-lime">Webhooks</h3>
        <p class="text-[0.86rem] leading-[1.65] text-tgx02-dim">Subscribe to <code class="font-tgx02-mono text-tgx02-ink">shipment.delivered</code> and friends. Deliveries retry for 24 hours with exponential backoff.</p>
      </article>
    </main>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tgx02-bg: #1b1d26;
  --color-tgx02-bg: oklch(0.2 0.02 265);
  --color-tgx02-panel: #21242f;
  --color-tgx02-panel: oklch(0.24 0.025 265);
  --color-tgx02-nav: #272b38;
  --color-tgx02-nav: oklch(0.28 0.03 265);
  --color-tgx02-hover: #2e3242;
  --color-tgx02-hover: oklch(0.32 0.03 265);
  --color-tgx02-codebg: #171923;
  --color-tgx02-codebg: oklch(0.18 0.02 265);
  --color-tgx02-code: #cfe3a8;
  --color-tgx02-code: oklch(0.88 0.08 125);
  --color-tgx02-edge: #363a4a;
  --color-tgx02-edge: oklch(0.36 0.03 265);
  --color-tgx02-ink: #e9eaf0;
  --color-tgx02-ink: oklch(0.93 0.01 260);
  --color-tgx02-dim: #a7abbb;
  --color-tgx02-dim: oklch(0.73 0.02 260);
  --color-tgx02-lime: #b6e84f;
  --color-tgx02-lime: oklch(0.85 0.19 130);
  --color-tgx02-limetint: #2c3826;
  --color-tgx02-limetint: oklch(0.32 0.05 130);
  --font-tgx02-sans: 'Inter Tight', system-ui, sans-serif;
  --font-tgx02-mono: 'JetBrains Mono', ui-monospace, monospace;
}

.tgx-02 {
  width: 100%;
  min-height: 100svh;
}
```

How this works

Grid stretches items to their row. A stretched rail has no travel, so sticky computes and never engages. self-start shrinks it to content height and the pinning starts working — the single most-searched grid bug, solved in one class.

The content track is guarded. minmax(0,1fr), not 1fr: a plain 1fr is minmax(auto,1fr), and one unwrapped curl example pushes the rail off-canvas.

Make it yours

  • Clear a fixed site header with top-16 instead of top-0.
  • Long pages: add max-h-[calc(100svh-2rem)] overflow-y-auto to the nav.
  • Move the rail right by swapping the children and the track order; sticky is unaffected.

Gotchas — read before shipping

  • sticky with no inset never pins — top-0 is mandatory.
  • Any ancestor with overflow-hidden becomes the sticky containing block and clips the effect.
  • Anchor targets need scroll-mt-* or your heading lands under the sticky rail.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Sticky-in-grid works in every engine since 2017 once alignment is set.

Techniques used in this demo

Search CodeFronts

Loading…