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.
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:
| Utility | CSS | Call sites in this repo |
|---|---|---|
flex | display: flex | 158 |
inline-flex | display: inline-flex | 57 |
flex-col | flex-direction: column | 35 |
flex-wrap | flex-wrap: wrap | 27 |
flex-1 | flex: 1 1 0% | 13 |
flex-row | flex-direction: row | 6 |
flex-auto / flex-initial / flex-none | — | 0 |
flex-grow / flex-grow-0 | — | 0 |
flex-shrink / flex-shrink-0 | — | 0 |
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
| Utility | Typical use elsewhere | Used here? |
|---|---|---|
flex / inline-flex | The base of virtually every one-axis layout | Yes — 158 + 57 = 215 call sites, the two most common utilities in the whole flex family |
flex-col / flex-row | Direction, often responsive (flex-col md:flex-row) | Yes — 35 + 6 = 41, mostly mobile-stacks-desktop-row patterns |
flex-wrap | Letting children wrap onto multiple lines | Yes — 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-none | Per-child basis tuning in complex multi-column layouts | No — zero call sites |
flex-grow / flex-grow-0 / flex-shrink / flex-shrink-0 | Independent grow/shrink ratios per child | No — 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
| Symptom | Cause | Fix |
|---|---|---|
| Children don't wrap onto a new line | Missing 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 expected | flex-1 on multiple siblings, all competing for the same leftover space | Only mark the one child that should expand; leave siblings without a flex-* grow class |
| Icon and text don't align on the same line | Used flex (block-level) inside inline text instead of inline-flex | Switch to inline-flex when the container sits inside a text flow |
| Layout doesn't reverse direction on mobile | No responsive prefix on the direction utility | Use flex-col md:flex-row (or the reverse) rather than a single fixed direction |
| Gap looks doubled on wrapped rows | Both gap-* and manual margins on children | Pick 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.
