Skip to main content
ASoc
Tutorial

Tailwind Flex: 6 of 12 Utilities, 296 Call Sites

296 flex-utility call sites across 68 files use 6 of Tailwind's 12 flex classes — the other six, all per-child grow/shrink tuning, are never needed.

The ASoc Team9 min read

Tailwind's flex utilities span twelve named classes — flex, inline-flex, three directions, two wrap modes, and five grow/shrink/basis shorthands. This codebase uses six of them, 296 times across 68 files, and the other six — flex-auto, flex-initial, flex-none, flex-shrink, flex-shrink-0, flex-grow, flex-grow-0 — appear zero times. That's not an oversight; it's what a component-driven layout actually needs once gap replaces the reasons those shorthands used to exist.

The short answer

flex sets display: flex; inline-flex does the same as an inline-level box. Direction (flex-row/flex-col), wrapping (flex-wrap) and the flex-1 "grow and shrink evenly" shorthand cover the vast majority of real layouts — this codebase's own 296 call sites never touch flex-auto, flex-initial, flex-none, or the standalone flex-grow/flex-shrink utilities at all.

The utilities, and what this codebase actually calls

A grep of every .tsx file for Tailwind's flex-family classes:

UtilityCSSCall sites in this repo
flexdisplay: flex158
inline-flexdisplay: inline-flex57
flex-colflex-direction: column35
flex-wrapflex-wrap: wrap27
flex-1flex: 1 1 0%13
flex-rowflex-direction: row6
flex-auto / flex-initial / flex-none0
flex-grow / flex-grow-00
flex-shrink / flex-shrink-00

296 total call sites across 68 of this repo's 126 component/route files, spanning 6 of the 12 named utilities.

flex is almost always paired with gap, never with manual spacing

inline-flex shows up 57 times, and every one of those is the Button atom's base class plus one-off badge and pill components — anywhere a link or label needs its icon and text on one baseline:

// src/components/atoms/Button.tsx
const base =
  "inline-flex items-center justify-center gap-2 rounded-lg px-6 py-3 ...";

The block-level flex (158 call sites) skews the same way: items-center and gap-* ride along on nearly every one, because this codebase reaches for flex to align things on one axis with even spacing, not to build a two-dimensional grid — that job goes to Tailwind's grid utilities elsewhere in the same files.

flex-col and responsive direction switches

Footer is the clearest example of flex-col/flex-row doing real responsive work, not just a static column stack:

// src/components/organisms/Footer.tsx
<div className="flex flex-col gap-12 xl:flex-row xl:items-start xl:justify-between xl:gap-10">
  {/* link columns */}
  <nav aria-label="Footer" className="flex flex-wrap gap-x-10 gap-y-10">
    {/* ... */}
  </nav>
  <div className="flex items-center justify-center gap-4 py-8 max-sm:flex-col">
    {/* legal links */}
  </div>
</div>

Three separate flex containers in one component: the outer wrapper stacks vertically on mobile and switches to a row past xl, the nav wraps its link columns onto as many lines as fit, and the bottom bar collapses back to a column under max-sm. All three read their spacing from gap, not margin utilities on individual children — which is exactly why this codebase never needed flex-auto or the standalone flex-grow/flex-shrink: those utilities exist to fine-tune how individual flex children compete for leftover space, and a gap-based layout with flex-1 on the one child that should fill remaining room covers that need without touching a per-child grow/shrink knob.

The mobile-drawer direction switch, three flex containers deep

Header's mobile navigation drawer nests flex containers three levels deep, switching direction at the xl breakpoint on every one of them at once:

// src/components/organisms/Header.tsx (trimmed)
<div className="fixed inset-y-0 right-0 z-9999 flex w-[85%] max-w-xs flex-col justify-between
                 xl:static xl:max-w-none xl:flex-1 xl:flex-row xl:items-center xl:justify-between">
  <nav aria-label="Primary">
    <ul className="flex flex-col gap-5 xl:flex-row xl:items-center 2xl:gap-8">
      {/* nav links */}
    </ul>
  </nav>
  <div className="mt-7 flex flex-col items-stretch gap-3 xl:mt-0 xl:flex-row xl:items-center">
    {/* sign-in / sign-up buttons */}
  </div>
</div>

Below xl, this is a full-height fixed drawer stacking its nav links and auth buttons in a single column (flex-col), each with its own gap. Past xl, three things happen on the same three containers: the drawer becomes a static, inline part of the header (xl:static), takes xl:flex-1 so it fills the remaining header width, and every one of its nested flex-col lists flips to xl:flex-row — the nav links go from a vertical list to a horizontal one, and the auth buttons go from stacked to side-by-side, with no separate desktop markup and no JavaScript involved in the switch.

flex-1: the one shorthand this codebase actually reaches for

13 call sites use flex-1 (flex: 1 1 0% — grow and shrink evenly, ignoring the child's own basis), always on exactly one child of a flex row that should expand to fill whatever space its siblings don't take — a search input next to a fixed-width button, a content column next to a fixed-width sidebar. That single shorthand does the job flex-grow-0/flex-shrink-0 combinations handle in more verbose codebases, because there's only ever one "let this one expand" child per container here, never a case requiring per-child grow/shrink ratios tuned independently.

The comparison

UtilityTypical use elsewhereUsed here?
flex / inline-flexThe base of virtually every one-axis layoutYes — 158 + 57 = 215 call sites, the two most common utilities in the whole flex family
flex-col / flex-rowDirection, often responsive (flex-col md:flex-row)Yes — 35 + 6 = 41, mostly mobile-stacks-desktop-row patterns
flex-wrapLetting children wrap onto multiple linesYes — 27, mostly nav links and badge/pill groups
flex-1"This child fills the remaining space"Yes — 13, always exactly one child per container
flex-auto / flex-initial / flex-nonePer-child basis tuning in complex multi-column layoutsNo — zero call sites
flex-grow / flex-grow-0 / flex-shrink / flex-shrink-0Independent grow/shrink ratios per childNo — flex-1 covers every "let this expand" case this codebase has

Why the other six never show up

The unused six aren't missing because nobody knows about them — they solve a problem this codebase's design system doesn't have. flex-auto/flex-initial/flex-none and the standalone grow/shrink utilities matter when several children in one container need independently tuned space-sharing rules (child A takes twice the leftover space of child B, child C never shrinks below its content size). Every flex container in this codebase either distributes space evenly via gap with no child claiming extra room, or has exactly one child marked flex-1 to absorb the remainder — a two-case pattern that flex + gap + occasional flex-1 covers completely, the same way the font-weight scale collapses to three real steps once a design system stops needing a checklist of every option shipped.

Troubleshooting

SymptomCauseFix
Children don't wrap onto a new lineMissing flex-wrap (default is nowrap)Add flex-wrap to the container, and gap-x-*/gap-y-* for spacing on both axes
One child grows way more than expectedflex-1 on multiple siblings, all competing for the same leftover spaceOnly mark the one child that should expand; leave siblings without a flex-* grow class
Icon and text don't align on the same lineUsed flex (block-level) inside inline text instead of inline-flexSwitch to inline-flex when the container sits inside a text flow
Layout doesn't reverse direction on mobileNo responsive prefix on the direction utilityUse flex-col md:flex-row (or the reverse) rather than a single fixed direction
Gap looks doubled on wrapped rowsBoth gap-* and manual margins on childrenPick one — gap alone handles both row and column spacing in a wrapped flex container

Frequently asked questions

What's the difference between flex and flex-1? flex sets display: flex on a container, turning its direct children into flex items. flex-1 is applied to a child, not the container — it sets flex: 1 1 0% so that child grows and shrinks to fill available space.

Do I need flex-grow if I'm already using flex-1? Usually not. flex-1 already includes grow and shrink behavior. The standalone flex-grow/flex-shrink utilities matter only when you need to tune those two independently per child, which this codebase's layouts never do.

Why does this site use gap instead of margins between flex children? gap sets spacing once on the container regardless of how many children exist or whether they wrap; margin-based spacing needs a :last-child exception (or a space-x-* utility) to avoid trailing space, and doesn't handle a wrapped grid of children cleanly.

Is flex-wrap the same as CSS Grid wrapping? No — flex-wrap lets a single-axis flex layout overflow onto additional lines, but each line is still a one-axis flex container. Grid, used elsewhere in this codebase for card layouts, defines both axes explicitly instead.

Why does this codebase never use flex-shrink-0 to stop something from shrinking? Because nothing here has a fixed-size sibling next to a flexible one that would otherwise get squeezed — Header's hamburger button and the Footer's logo sit in single-item containers, not alongside a flex-1 element competing for the same row. flex-shrink-0 earns its place in a layout with, say, a fixed-width avatar next to a growing name column; add one here and it would have nothing to protect against.

Templates in this post

ASoc Mind, ASoc Momentum and ASoc Neuron are Next.js + Tailwind landing page templates, built with the same flex + gap layout patterns audited above.

Browse the full sets: Next.js landing page templates, Tailwind landing page templates.

Keep reading

Tutorial10 min read

Tailwind Font Weight: 9 Named Steps, 4 This Codebase Uses

193 font-weight utility calls across this codebase, spanning only 4 of Tailwind's 9 named steps — traced to two atoms that set the hierarchy once.

Read more
Tutorial9 min read

Tailwind Grid: 26 Files, and Not One col-span

A 538-page site's whole grid vocabulary is three utilities — plus the display:contents trick that reorders a product page on mobile without duplicating state.

Read more