CSS Grid wraps items by placing them into declared cells left-to-right, then continuing on the next row once the current row is full, which is why the grid-template-columns declaration controls when content overflows a row. When you set a container to display: grid and define an explicit column template, the browser fills each cell with the next available child in source order, dropping to a new row only when no more columns exist. That placement is the default wrap behavior of the layout mode; it is not a property called wrap the way flex-wrap is in Flexbox. The track declarations you write — how many columns, how wide each one is, and how much gap sits between them — directly decide whether children fit on one row, spread across several, or push past the visible container. The CSS Grid Generator produces a validated .grid rule with declared columns, rows, gap, and item alignment so that wrapping behaves predictably from the moment the rule lands in your stylesheet.

how to make css grid wrap
how to make css grid wrap

What Wrapping Means in a CSS Grid Context

CSS Grid is a two-dimensional layout model. The wrapping it performs is row-by-row cell assignment, not the single-axis line wrap that Flexbox offers through flex-wrap. Once you declare grid-template-columns with three tracks, the engine places the first three children in row one, the next three in row two, and so on. You are not asking the grid to wrap; the wrap is a built-in consequence of having a finite number of column tracks. The wrap happens automatically, but only as long as the tracks stay equal. The moment one track grows past its share, the visible grid stops behaving like an equal-track wrap and starts producing an overflow column.

Two situations frequently get mistaken for "the grid is not wrapping." First, content overflow happens when a track expands beyond its declared size because its min-content contribution pushes it wider than the declared fr space. A single long URL, an unbreakable word, or an oversized image in one cell can stretch that track and force the layout engine to either push neighbors off-grid or break the row before the column count is reached. Second, no wrap row appears when grid-auto-rows is undeclared and the implicit row the engine creates has no defined height, which can hide the new row inside the container or push it below the visible viewport. Both cases are fixed by making the tracks explicit, equal, and bounded, which is the contract the CSS Grid Generator applies to every output rule.

A practical wrap test is straightforward: pick a number of children larger than your declared column count. Three columns and seven items should produce three on the first row, three on the second, and one on a third. If the seventh child visually overlaps the third row or escapes the container, the tracks are not actually equal — a long word or wide image inside a track is forcing the track to grow, and your wrap is being destroyed by min-content sizing. The fix is the minmax(0, 1fr) shape that the generator uses, because the zero minimum lets each track shrink back down regardless of its content.

Setting Up an Explicit Wrapping Grid with the Generator

The CSS Grid Generator gives you a bounded builder for the exact declarations that drive row-by-row wrapping. Open the tool and you will see three number inputs, two alignment selects, a live preview area, and a generated CSS block. Working through the controls in order produces a rule that wraps correctly the first time it is pasted into a stylesheet.

  1. Enter a whole-number column count from 1 through 12 in the columns field. This is the number of cells per row and therefore the trigger for when wrapping to a new row occurs.
  2. Enter a whole-number row count from 1 through 12 in the rows field. This sets how many rows the preview and the generated rule reserve up front; additional rows after the row count fills still appear because the engine creates implicit tracks, but the declared tracks give the wrap a known shape.
  3. Enter a pixel gap from 0 through 100 in the gap field. The same value is applied to both row-gap and column-gap through the shorthand gap property, which MDN documents as applying equal spacing to both axes.
  4. Pick a justify-items value from stretch, start, center, or end. This sets how every grid item is positioned along the inline axis inside its cell.
  5. Pick an align-items value from the same four options. This sets the corresponding default alignment on the block axis.
  6. Watch the live preview as you edit. When every field is valid, the preview shows the current track counts, gap, and alignment values immediately. When any field is invalid, the preview falls back to a safe three-column by two-row default rather than displaying stale input.
  7. Click Generate CSS and copy the resulting .grid rule. If clipboard permission is blocked, select the code in the output block manually.

Editing any control after generation clears the previous CSS block, the previous error, and the previous copy status. This keeps the displayed rule in sync with the values you are inspecting in the preview, which avoids pasting a stale rule into a layout that has since changed. The preview and the generated CSS are derived from the same validated configuration, so they cannot drift apart within a single edit cycle.

Reading the Generated repeat() and minmax() Tracks

The generated rule begins with display: grid to establish a grid formatting context. It then emits grid-template-columns and grid-template-rows using repeat(n, minmax(0, 1fr)). Understanding what each token does is the difference between copying the rule blindly and being able to debug wrapping problems later.

repeat(n, minmax(0, 1fr)) writes the same track function n times in a single declaration instead of duplicating 1fr 1fr 1fr for a three-column grid. The n is the validated track count from 1 to 12. Inside minmax(), the zero minimum is the critical part: it lets a track shrink down to nothing when its content is small, instead of forcing the track to remain at least as wide as the longest unbreakable string inside it. Without that zero, a long URL or a wide image in one cell can push that track past its fair share of the container, throwing off the wrap and pushing siblings into the next row prematurely. The 1fr ceiling keeps every track equal once space is divided, which is the practical equal-track pattern the generator is built around.

The gap declaration in the same rule uses one pixel length, so the same gutter appears between both rows and columns. Zero is valid and produces no gutter at all. The generator deliberately limits the value to 100px because the tool is a bounded visual builder rather than an arbitrary CSS editor. It rejects 101 or 100.5 instead of silently clamping them. A field that is empty, signed, decimal, whitespace-padded, unit-suffixed, or longer than 32 UTF-16 code units returns an explicit error and produces no generated CSS, so the rule you copy is always parseable by the browser.

Aligning Items Inside Each Wrapped Cell

Alignment inside the cells is governed by two CSS properties that the generator exposes as closed enum selects. justify-items controls how every grid item is justified along the inline axis inside its grid area. align-items supplies the matching default alignment along the block axis. The four values offered for each — stretch, start, center, end — cover the everyday cases without inviting arbitrary CSS injection.

ValueInline axis (justify-items)Block axis (align-items)
stretchFills the cell horizontally when item sizing permitsFills the cell vertically when item sizing permits
startItem sits at the inline-start edge of its cellItem sits at the block-start edge of its cell
centerItem is centered between the inline edgesItem is centered between the block edges
endItem sits at the inline-end edge of its cellItem sits at the block-end edge of its cell

These settings align items inside their assigned areas. They are not justify-content or align-content, which align the grid tracks as a group inside a larger container, and they do not place individual items via grid-row, grid-column, or grid-area. If your layout needs different alignment per row or per cell, the generator output is the starting point; you still write the per-item overrides yourself.

A safety detail worth noting: the alignment values pass strict enum validation against exactly the four internal values listed above. A crafted value such as center followed by another declaration is rejected before the string is generated, even if a caller bypasses the visible select control. The CSS property names, punctuation, units, repeat(), minmax(), and fr tokens in the output are fixed by the implementation, so the rule is deterministic rather than a recombination of user-supplied fragments.

Bounded Inputs and What the Generator Will Reject

Because the tool is designed to produce standards-anchored CSS rather than free-form stylesheet text, every input has a hard envelope. Columns and rows accept only decimal integers from 1 through 12. Gap accepts only decimal integers from 0 through 100. Anything outside those ranges, anything with a sign or decimal point, anything with a unit suffix or surrounding whitespace, and anything longer than 32 UTF-16 code units returns an error and generates no output.

This strict parsing is deliberate. The generator never silently coerces 13 columns into 12, never rounds 100.5 to 100, and never lets a stray px suffix slip through into the emitted declaration. The result is that the number you type is the number you get in the CSS, which keeps wrap behavior predictable across restarts of the tool.

The preview follows the same discipline. It is always visible, and it derives from the same validated configuration that drives the generated CSS. When a field is invalid, the preview resets to the documented safe three-column by two-row default rather than rendering a stale or partially interpreted layout. If the preview looks like the safe default, the cause is an input error in one of the fields above it, not a bug in the tool. Large gaps or twelve-by-twelve grids can make sample cells very small or require scrolling, but the output still contains the exact requested values.

Adding Responsive Wrapping on Top of the Generated Rule

The generated rule is a single explicit grid. It does not automatically adapt its column count to viewport size, because each track count is fixed by the input you supplied. For a layout that should drop from four columns on desktop to two on tablet to one on mobile, the generator output is the desktop starting point; the responsive rules are added separately.

Three practical extensions cover most real layouts. Media queries let you swap the entire grid-template-columns declaration at breakpoint boundaries. Container queries do the same in response to a parent container's inline size, which works well inside reusable components. The auto-fit pattern with minmax(min, 1fr) creates a wrapping track count that grows and shrinks with available space, which is the closest match to a true wrap behavior because the engine decides how many tracks fit at any given width.

None of these patterns appear in the copied output, because the generator is a bounded builder rather than a responsive framework. Its job is to produce a validated, parseable rule for one explicit grid. For a deeper look at how repeat() and minmax() interact inside a flexible grid, the walkthrough on making a CSS grid flexible with fr and minmax extends the same track vocabulary for responsive cases. Use the generated rule as a starting point and adapt it to the actual content and breakpoints of the project.

The MDN reference for align-items is the place to verify the exact alignment values used in the rule. The CSS Grid Layout Module Level 2 specification anchors the grid-template-columns, grid-template-rows, repeat(), fr, and gap behavior the generator relies on, so the rule you copy is standards-based rather than vendor-specific. Finally, remember that visual grid reordering should never replace logical document order. Keyboard navigation and assistive technology follow the source, so wrap placement that looks correct visually can still leave the underlying markup in the wrong reading order. Build the semantic HTML first, then adapt the generated declarations to that structure.