Tailwind CSS 16 🎨 Dynamic Arbitrary Grid Sizes without Configuration
Tailwind CSS v4 eliminated a long-standing limitation: grid utilities no longer require configuration for non-standard column or row counts. Where v3 forced developers to either extend the theme.gridTemplateColumns configuration or drop into arbitrary value syntax like grid-cols-[repeat(15,minmax(0,1fr))], v4 generates utilities dynamically. The class grid-cols-15 works out of the box, producing exactly the CSS you would expect . The same applies to spacing utilities, which are now derived from a single --spacing variable and accept any numeric value without configuration .
This change simplifies markup and reduces the need for arbitrary value syntax in the common case. The arbitrary value syntax still exists for values that are not simple numbers — custom track lists, CSS variables, and functions like minmax() — but the everyday grid with a non-standard column count no longer requires it .
Key point: Tailwind v4 generates grid-cols-* utilities dynamically for any integer value without configuration. grid-cols-15 produces repeat(15, minmax(0, 1fr)). Use arbitrary values with square brackets (grid-cols-[...]) for complex track definitions, and the parenthesis syntax (grid-cols-(--var)) for CSS variables.
Why dynamic grid values exist
The configuration burden problem. In v3, a grid with 15 or 17 or 24 columns required extending the theme configuration. The configuration file grew with every non-standard column count, and the values were duplicated between the config and the markup. v4 removes the configuration step entirely for numeric counts .
The arbitrary value verbosity problem. The v3 workaround was grid-cols-[repeat(15,minmax(0,1fr))], which is verbose and obscures the intent. The v4 dynamic form grid-cols-15 states the column count directly and generates the same CSS .
The consistency problem. The dynamic values are derived from the same pattern: repeat(N, minmax(0, 1fr)). Every column count produces equal-width columns, and the minmax(0, 1fr) prevents content from expanding a track beyond its share .
The arbitrary value problem. Dynamic values cover the common case — an integer column count — but not the complex cases. A grid with mixed track sizes, named lines, or minmax() with different parameters still needs the arbitrary value syntax. The two forms coexist: dynamic for the simple case, arbitrary for the complex one .
The upgrade problem. The v4 upgrade tool simplifies most grid-cols-[repeat(N,minmax(0,1fr))] usages to grid-cols-N automatically, so existing codebases benefit from the change without manual edits .
a. Dynamic column counts
Any positive integer works as a column count. The utility generates a grid with that many equal-width columns.
<div class="grid grid-cols-15 gap-4">
<!-- 15 equal columns -->
</div>
The generated CSS is:
.grid-cols-15 {
grid-template-columns: repeat(15, minmax(0, 1fr));
}
The minmax(0, 1fr) is the key detail. Without it, a grid item with content wider than its track would expand the track. The minmax(0, ...) sets the minimum track size to zero, so tracks stay equal even when content is long .
The standard counts — 1 through 12 — are still available and produce the same pattern. The difference is that 13 and above now work without configuration.
<div class="grid grid-cols-1">...</div>
<div class="grid grid-cols-12">...</div>
<div class="grid grid-cols-24">...</div>
The dynamic behavior applies to any integer, not just the values that were previously defined in the default theme.
b. Dynamic row counts
The same dynamic behavior applies to grid-rows-*.
<div class="grid grid-rows-8 grid-flow-col gap-4">
<!-- 8 equal rows -->
</div>
The generated CSS is:
.grid-rows-8 {
grid-template-rows: repeat(8, minmax(0, 1fr));
}
Rows are defined less often than columns because rows usually size to their content, but when a grid has a fixed height and a specific row structure, the dynamic row count is available without configuration.
c. Combining with other grid utilities
The dynamic column and row counts compose with the rest of the grid utilities.
<div class="grid grid-cols-15 grid-rows-8 gap-4">
<!-- 15 columns, 8 rows -->
</div>
Spans work the same way:
<div class="grid grid-cols-15 gap-4">
<div class="col-span-5">Spans 5 columns</div>
<div class="col-span-10">Spans 10 columns</div>
</div>
The col-span-* utilities accept dynamic values as well. col-span-5 and col-span-10 work without configuration, and the spans add up to the total column count.
Responsive variants apply:
<div class="grid grid-cols-4 md:grid-cols-8 lg:grid-cols-12 xl:grid-cols-16 gap-4">
<!-- 4 columns on mobile, 8 on md, 12 on lg, 16 on xl -->
</div>
The dynamic values make responsive column counts easier because the intermediate breakpoints do not require custom theme entries.
d. When to use arbitrary values instead
The dynamic form covers integer column and row counts. The arbitrary value syntax is still needed for track definitions that are not a simple repetition of equal columns.
Mixed track sizes.
<div class="grid grid-cols-[200px_1fr_auto]">
<!-- Fixed 200px, flexible, content-sized -->
</div>
Named grid lines.
<div class="grid grid-cols-[sidebar-start_1fr_sidebar-end_content-start_2fr_content-end]">
</div>
Repeat with different parameters.
<div class="grid grid-cols-[repeat(3,minmax(100px,1fr))]">
<!-- 3 columns with a 100px minimum -->
</div>
Functions like fit-content() or max-content.
<div class="grid grid-cols-[fit-content(200px)_1fr]">
</div>
The dynamic form is a shorthand for repeat(N, minmax(0, 1fr)). When the track definition deviates from that pattern, the arbitrary value syntax is required .
e. CSS variables with parenthesis syntax
For grids whose column definition is stored in a CSS variable, v4 provides the parenthesis syntax.
<div class="grid grid-cols-(--my-columns)">
<!-- Uses var(--my-columns) as the grid-template-columns value -->
</div>
This is shorthand for grid-cols-[var(--my-columns)]. The variable can be defined in a @theme block, in a :root selector, or inline with a style attribute .
@theme {
--columns-16: repeat(16, minmax(0, 1fr));
}
<div class="grid grid-cols-(--columns-16)">
<!-- 16 equal columns from a theme variable -->
</div>
The parenthesis syntax is the v4 replacement for the older grid-cols-[var(--my-columns)] form. The bracket form still works for CSS variables, but the parenthesis form is shorter and is the recommended syntax .
f. Responsive and state variants
Dynamic grid values work with every variant.
<div class="grid grid-cols-4 md:grid-cols-8 lg:grid-cols-12 gap-4">
</div>
<div class="grid grid-cols-12 hover:grid-cols-6 transition-all">
</div>
The state variants — hover, focus, active — apply to the grid utilities the same way they apply to any other utility. A grid that changes its column count on hover is unusual, but the mechanism is available.
The responsive pattern is the common case: a small column count on mobile, more on tablet, more on desktop. The dynamic values mean the intermediate breakpoints do not need custom theme entries.
Complete Example Session
<!-- ============================================
PART 1: DYNAMIC COLUMN COUNT
============================================ -->
<div class="grid grid-cols-15 gap-4">
<div>Item</div>
<div>Item</div>
<div>Item</div>
</div>
<!-- ============================================
PART 2: DYNAMIC ROW COUNT
============================================ -->
<div class="grid grid-rows-8 grid-flow-col gap-4">
<div>Item</div>
</div>
<!-- ============================================
PART 3: COMBINED ROWS AND COLUMNS
============================================ -->
<div class="grid grid-cols-15 grid-rows-8 gap-4">
<div>Cell</div>
</div>
<!-- ============================================
PART 4: DYNAMIC SPANS
============================================ -->
<div class="grid grid-cols-15 gap-4">
<div class="col-span-5">Five columns</div>
<div class="col-span-10">Ten columns</div>
</div>
<!-- ============================================
PART 5: RESPONSIVE COLUMN COUNTS
============================================ -->
<div class="grid grid-cols-4 md:grid-cols-8 lg:grid-cols-12 xl:grid-cols-16 gap-4">
<div>Item</div>
</div>
<!-- ============================================
PART 6: ARBITRARY MIXED TRACKS
============================================ -->
<div class="grid grid-cols-[200px_1fr_auto] gap-4">
<aside>Sidebar</aside>
<main>Content</main>
<button>Action</button>
</div>
<!-- ============================================
PART 7: ARBITRARY REPEAT WITH MINIMUM
============================================ -->
<div class="grid grid-cols-[repeat(3,minmax(100px,1fr))] gap-4">
<div>Item</div>
<div>Item</div>
<div>Item</div>
</div>
<!-- ============================================
PART 8: CSS VARIABLE WITH PARENTHESIS
============================================ -->
<div class="grid grid-cols-(--my-columns) gap-4">
<div>Item</div>
</div>
<!-- ============================================
PART 9: THEME VARIABLE FOR GRID
============================================ -->
<!-- In the theme: --columns-16: repeat(16, minmax(0, 1fr)); -->
<div class="grid grid-cols-(--columns-16) gap-4">
<div>Item</div>
</div>
<!-- ============================================
PART 10: DYNAMIC WITH VARIANTS
============================================ -->
<div class="grid grid-cols-12 hover:grid-cols-6 transition-all gap-4">
<div>Item</div>
</div>
These ten parts cover dynamic column count, dynamic row count, combined rows and columns, dynamic spans, responsive column counts, arbitrary mixed tracks, arbitrary repeat with a minimum, CSS variable with parentheses, a theme variable for grid, and dynamic with variants.
Quick Reference
Dynamic Grid Values
| Utility | Generated CSS |
|---|---|
grid-cols-15 | repeat(15, minmax(0, 1fr)) |
grid-cols-24 | repeat(24, minmax(0, 1fr)) |
grid-rows-8 | repeat(8, minmax(0, 1fr)) |
col-span-5 | span 5 / span 5 |
Arbitrary Value Syntax
| Form | Example | Use case |
|---|---|---|
| Brackets | grid-cols-[200px_1fr] | Custom track list |
| Parentheses | grid-cols-(--var) | CSS variable |
| Brackets with var | grid-cols-[var(--var)] | CSS variable (legacy) |
When to Use What
| Track definition | Syntax |
|---|---|
| N equal columns | grid-cols-N |
| Mixed sizes | grid-cols-[200px_1fr_auto] |
| CSS variable | grid-cols-(--var) |
| Named lines | grid-cols-[name_1fr_name_2fr] |
| Custom repeat | grid-cols-[repeat(3,minmax(100px,1fr))] |
Responsive Patterns
| Pattern | Purpose |
|---|---|
grid-cols-4 md:grid-cols-8 | Responsive column count |
grid-cols-12 lg:grid-cols-16 | More columns on desktop |
col-span-5 col-span-10 | Dynamic spans |
Best Practices
✅ Do This:
<!-- Use the dynamic form for equal columns -->
<div class="grid grid-cols-15 gap-4">
<!-- Use arbitrary values for mixed tracks -->
<div class="grid grid-cols-[200px_1fr_auto]">
<!-- Use parenthesis syntax for CSS variables -->
<div class="grid grid-cols-(--my-columns)">
<!-- Use responsive variants for column counts -->
<div class="grid grid-cols-4 md:grid-cols-8 lg:grid-cols-12">
<!-- Use dynamic spans -->
<div class="col-span-5">
❌ Don’t Do This:
<!-- Verbose arbitrary value for equal columns -->
<div class="grid grid-cols-[repeat(15,minmax(0,1fr))]"> <!-- ❌ use grid-cols-15 -->
<!-- Arbitrary value for a simple column count -->
<div class="grid-cols-[15]"> <!-- ❌ use grid-cols-15 -->
<!-- Missing minmax(0, 1fr) in arbitrary repeat -->
<div class="grid-cols-[repeat(15,1fr)]"> <!-- ⚠️ tracks may expand -->
<!-- Using arbitrary value when dynamic works -->
<div class="grid-cols-[repeat(8,minmax(0,1fr))]"> <!-- ❌ use grid-cols-8 -->
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Utility not generated | Used v3 with v4 syntax | Update to v4 |
| Tracks expand unexpectedly | Missing minmax(0, 1fr) | Use dynamic form or add minmax(0, 1fr) |
| CSS variable not applied | Used bracket form in v4 | Use parenthesis syntax |
| Verbose markup | Used arbitrary value for equal columns | Use grid-cols-N |
| Responsive counts too sparse | Only defined standard breakpoints | Add intermediate counts |
| Span exceeds column count | Spans do not match the grid | Verify the sum |
Real-World Examples
1. 15 Column Grid
<div class="grid grid-cols-15 gap-2">
</div>
2. 24 Column Grid
<div class="grid grid-cols-24 gap-1">
</div>
3. Responsive Columns
<div class="grid grid-cols-4 md:grid-cols-8 lg:grid-cols-12">
</div>
4. Mixed Tracks
<div class="grid grid-cols-[200px_1fr_auto]">
</div>
5. CSS Variable
<div class="grid grid-cols-(--columns-16)">
</div>
6. Theme Variable
@theme {
--columns-16: repeat(16, minmax(0, 1fr));
}
7. Dynamic Span
<div class="col-span-5">
</div>
8. Repeat with Minimum
<div class="grid grid-cols-[repeat(3,minmax(100px,1fr))]">
</div>
9. Rows
<div class="grid grid-rows-8 grid-flow-col">
</div>
10. Hover Variant
<div class="grid grid-cols-12 hover:grid-cols-6">
</div>
Visual
Dynamic vs Arbitrary
┌──────────────────────────────────────────────────────────────┐
│ DYNAMIC (simple integer): │
│ grid-cols-15 │
│ └── repeat(15, minmax(0, 1fr)) │
│ │
│ ARBITRARY (custom track list): │
│ grid-cols-[200px_1fr_auto] │
│ └── 200px 1fr auto │
│ │
│ PARENTHESIS (CSS variable): │
│ grid-cols-(--my-columns) │
│ └── var(--my-columns) │
└──────────────────────────────────────────────────────────────┘
The Generated CSS
┌──────────────────────────────────────────────────────────────┐
│ <div class="grid grid-cols-15 gap-4"> │
│ │
│ Generated: │
│ .grid-cols-15 { │
│ grid-template-columns: repeat(15, minmax(0, 1fr)); │
│ } │
│ │
│ The minmax(0, 1fr) prevents content from expanding tracks. │
└──────────────────────────────────────────────────────────────┘
When to Use Each Syntax
┌──────────────────────────────────────────────────────────────┐
│ N equal columns: │
│ └── grid-cols-N │
│ │
│ Mixed track sizes: │
│ └── grid-cols-[200px_1fr_auto] │
│ │
│ CSS variable: │
│ └── grid-cols-(--my-columns) │
│ │
│ Custom repeat: │
│ └── grid-cols-[repeat(3,minmax(100px,1fr))] │
└──────────────────────────────────────────────────────────────┘
Responsive Column Counts
┌──────────────────────────────────────────────────────────────┐
│ MOBILE TABLET DESKTOP │
│ grid-cols-4 md:grid-cols-8 lg:grid-cols-12 │
│ 4 equal cols 8 equal cols 12 equal cols │
│ │
│ No configuration needed for any of these values. │
└──────────────────────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
| Dynamic column count | grid-cols-15 |
| Dynamic row count | grid-rows-8 |
| Generated CSS | repeat(N, minmax(0, 1fr)) |
| Configuration | None required |
| Arbitrary tracks | grid-cols-[200px_1fr_auto] |
| CSS variable | grid-cols-(--var) |
| Dynamic spans | col-span-5 |
| Responsive | md:grid-cols-8 |
| v3 equivalent | grid-cols-[repeat(N,minmax(0,1fr))] |
| Upgrade tool | Simplifies v3 arbitrary values |
Key takeaways:
- Tailwind v4 generates grid utilities dynamically for any integer.
grid-cols-15andgrid-rows-8work without configuration, producingrepeat(N, minmax(0, 1fr)). - The dynamic form is the shorthand for equal columns. It covers the common case of a grid with a non-standard column count. The arbitrary value syntax is reserved for complex track definitions.
- Arbitrary values handle mixed tracks.
grid-cols-[200px_1fr_auto]sets custom track sizes, named lines, and functions likeminmax()andfit-content(). - The parenthesis syntax is for CSS variables.
grid-cols-(--my-columns)is the v4 shorthand forgrid-cols-[var(--my-columns)]. - Dynamic spans work the same way.
col-span-5andcol-span-10are generated dynamically and compose with the column count. - Responsive variants apply.
grid-cols-4 md:grid-cols-8 lg:grid-cols-12changes the column count at breakpoints without custom theme entries. - The v4 upgrade tool simplifies existing code. Most
grid-cols-[repeat(N,minmax(0,1fr))]usages are converted togrid-cols-Nautomatically .
Remember: Tailwind v4 removed the configuration step for non-standard grid sizes. The dynamic utilities accept any integer and generate the expected repeat(N, minmax(0, 1fr)) CSS. The arbitrary value syntax still exists for the cases the dynamic form cannot express: mixed track sizes, named lines, custom minmax() parameters, and CSS variables. The rule is simple: if the grid is N equal columns, use grid-cols-N; if it is anything else, use the brackets. This keeps the markup clean for the common case and precise for the complex one.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!