CSS Grid Generator

Set columns, rows and gaps, paint named grid areas onto a live grid, and copy matching CSS and HTML. Up to 12 tracks each way, free, no sign-up.

🌐 Español

header
sidebar
main
Column sizes
Row sizes
Template areas β€” pick one and paint cells in the grid below
Output style

πŸ”’ Private by design: everything runs locally in your browser and never uploaded to any server.

Painting areas onto a grid instead of counting quoted tokens

Writing grid-template-areas by hand is a copy-editing job disguised as a layout job. Each row is a quoted string, every string needs exactly one word per column, and a single missing token invalidates the declaration outright. Nothing warns you. The layout just falls back to auto-placement and you go hunting.

This page replaces that with a matrix you click on. The grid opens with three columns of 1fr, two rows of auto, ten-pixel gaps, and a header, sidebar and main layout already painted so there is something to take apart. Above the matrix sit chips, one per area name plus an Erase chip. Click a chip to make that area active, then press and drag across cells to fill them. Each cell shows either its area name or a dot when it is empty, and the small remove button on a chip deletes the area and clears every cell it occupied.

New areas come from the text box below the chips: type a name and press Enter or click + Add area. The name is sanitized on the way in, because it has to survive as a CSS identifier. Everything outside letters, digits, hyphens and underscores is stripped, so my area becomes myarea, while side-bar passes through untouched. A name starting with a digit or a hyphen cannot be an identifier at all, so the box simply clears itself.

The rectangle rule, and how strictly this builder enforces it

CSS requires every named area to occupy a solid rectangle. An L-shape, or the same name painted in two disconnected blocks, is invalid, and a browser that meets an invalid grid-template-areas value discards the whole declaration rather than salvaging the parts that were fine.

The generator refuses to put you in that position, and it is worth knowing how bluntly. The moment any one area stops being rectangular, a notice names it and the output loses not just that area but the entire grid-template-areas block and every per-area rule alongside it. The HTML pane switches to generic numbered cells at the same time. That is a deliberate all-or-nothing choice: partial output would look plausible and behave wrongly.

Track units, and the number box that vanishes on a keyword

Every column and every row is a track with two controls, a number and a unit. The unit list runs fr, px, %, em, rem, vw, vh, auto, min-content and max-content, and the last three hide the number box, since a keyword track takes no value. A mixed row is written exactly as you would type it, so a 200px sidebar, a flexible middle and a content-sized rail come out as 200px 1fr min-content.

Numbers are cleaned on entry. Negative values become zero, and anything longer than four decimal places is rounded. Gaps use their own, shorter unit list of px, em, rem and %, with row gap and column gap set separately. When both match, the output collapses to the one-value shorthand; when they differ you get the two-value form in row-then-column order, so a roomy 24-pixel row gap with tight 8-pixel columns writes as gap: 24px 8px.

Rebuilding the default header, sidebar and main shell

  1. Set Columns and Rows at the top. Both accept 1 to 12.
  2. Give each track a size in the Column sizes and Row sizes strips underneath, choosing a unit per track.
  3. Set Row gap and Column gap, each with its own number and unit.
  4. Type an area name, click + Add area, then click its chip and drag across the cells that area should cover. Use Erase to empty cells again.
  5. Choose an Output style, either Template areas or Line-based.
  6. Click Copy CSS, then Copy HTML, and paste both into your project.

Left untouched, the starting layout produces this:

.grid-container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: auto auto;
  gap: 10px;
  grid-template-areas:
    "header header header"
    "sidebar main main";
}

.grid-area-header { grid-area: header; }

.grid-area-sidebar { grid-area: sidebar; }

.grid-area-main { grid-area: main; }

Template areas or explicit line numbers, same layout either way

Switching Output style to Line-based describes the identical arrangement with different properties. The grid-template-areas block disappears from the container, and each child gets explicit line placement computed from where you painted it: the header becomes grid-column: 1 / span 3 with grid-row: 1 / span 1, the sidebar takes column 1 of row 2, and main spans columns 2 to 3 of that row.

Neither style is better. Template areas read like a map of the page and are easier to hand to someone else. Line placement is easier to override in a media query, where you often want to move one child without rewriting the container. Since both are derived from the same painted matrix, you can flip between them at any point and compare.

The HTML pane, and the class names it commits you to

The second output box is example markup whose classes line up with the CSS exactly. Whenever you have named areas and they are all rectangular, that means one <div> per distinct area, classed grid-area- plus the area name, with the name as its visible text, in either output style. Without named areas you get numbered <div class="grid-item"> elements instead, one per cell.

Those class names are a small commitment worth making consciously. Rename an area inside the generator and both panes update together, but rename it later in your own stylesheet and you have two places to keep in step. The live preview above uses the very same generated stylesheet, scoped so it cannot leak onto the rest of the page, and it is injected as text rather than as markup, so a painted area name has no route into anything executable.

When the layout is settled, CSS Minifier and Formatter will compress the stylesheet, CSS Gradient Generator handles the backgrounds that go inside these cells, and HTML Table Generator is the better tool when the content is genuinely tabular data rather than page structure. More sit on the generators hub.

See it in action

Screenshot of the CSS Grid Generator tool with a visual grid builder with named areas laid out over a live preview, and the matching CSS underneath it - grid-template-columns, grid-template-rows, gap and grid-template-areas - updating as the layout changes
CSS Grid Generator mid-process: a visual grid builder with named areas laid out over a live preview, and the matching CSS underneath it - grid-template-columns, grid-template-rows, gap and grid-template-areas - updating as the layout changes.
Diagram: where the work happens on a SysFenix page that has no file input at all: the tool arrives as ordinary JavaScript inside the page, works the answer out on your own device and renders it in place, so the upload, queue and server-side record a typical online tool needs never happen
Where the work happens on a SysFenix page that has no file input at all: the tool arrives as ordinary JavaScript inside the page, works the answer out on your own device and renders it in place, so the upload, queue and server-side record a typical online tool needs never happen.

Frequently asked questions

I painted an L-shaped region and every area rule vanished at once. Is that a bug?

It is deliberate, though it is blunter than it looks. A browser throws away an entire grid-template-areas declaration if any single named area is not a solid rectangle, so rather than hand you CSS that silently does nothing, the generator drops the whole areas block and all of the per-area rules until the shape is fixed. A red notice names the offending area while that is happening.

The number box next to one of my tracks disappeared. Why?

Because you picked a keyword unit. The auto, min-content and max-content options size a track from its own content and take no number at all, so the numeric field is hidden rather than left there doing nothing. Switch that track back to fr, px or any other measured unit and the box returns.

My new area name would not save. What is it rejecting?

Grid area names have to be valid CSS identifiers, so the box strips out anything that is not a letter, digit, hyphen or underscore, and then refuses a name that starts with a digit or a hyphen by clearing itself. Typing a two-word name collapses it into one word, which usually works fine, but a name beginning with a number will simply never take.

How many columns and rows can this build?

One to twelve of each, and a value typed outside that range is pulled back to the nearest end. Changing the count keeps whatever you had already painted in the cells that still exist, so widening a grid from three columns to four leaves your existing areas untouched and adds a blank column on the right.

Does the line-based output need rectangular areas as well?

Yes. Both output styles are computed from the same painted matrix, and the line-based spans come from each area's bounding box, so a non-rectangular area is excluded from that mode for the same reason it is excluded from the other one. Switching output styles is not a way around the rectangle rule.

What ends up in the HTML pane when I have not named any areas?

One numbered div per grid cell, all sharing the same class, with the count equal to your rows multiplied by your columns. They flow into the grid in source order without any explicit placement, which is exactly what you want for a gallery or a card list where every item is interchangeable.

Related tools