cnc-cards
A card grid that keeps the insides of its cards aligned. Columns fit themselves to the available width, and each card's own rows are a subgrid of the container's — so every image is the same height, every title sits on the same line, and every footer lines up along the bottom, however uneven the text is. It is pure CSS: no controller, no JavaScript, nothing to hydrate.
Quick start
Set --card-rows to the number of sections each card has, then give every card
exactly that many direct children. Here it is three: a banner, a body, and a footer.
<cnc-cards style="--card-width: 220px; --card-rows: 3; gap: 1rem">
<div class="rounded-lg overflow-hidden">
<div class="banner"></div> <!-- row 1 -->
<div class="p-4">…</div> <!-- row 2 -->
<div class="px-4 pb-4">…</div> <!-- row 3 -->
</div>
…
</cnc-cards>
Properties
There are no attributes. The widget is configured entirely through CSS custom properties and the
ordinary gap, which is why every example on this page sets them in a
style.
| Custom property | Default | Purpose |
|---|---|---|
| --card-width | 260px | The narrowest a column may get before the grid drops to fewer columns. Not a fixed width — columns stretch to share the space. |
| --card-rows | 4 | How many rows each card claims, and therefore how many of its children get aligned with its neighbours'. |
| gap | 0 | The ordinary grid gap. Zero by default, so cards touch until you say otherwise. |
A cards array is declared on the controller and read nowhere. The widget's whole
template is <slot></slot> — cards are markup you write, not data you
pass.
Things to know
-
Get
--card-rowsright or the card breaks. It is not a hint. A card with three children under--card-rows: 1renders all three in the same track, on top of one another. -
The card is the direct child; its sections are that child's children.
Wrapping a card in an extra
<div>makes the wrapper the card and collapses the alignment — the subgrid only reaches one level down. -
A card cannot set its own padding on the outer element.
The card becomes a grid with
row-gap: 0, so padding on it pushes every row in. Pad the sections instead, which is why the examples here usepx-4 pt-4on the parts rather thanp-4on the card. -
Row gaps come from the sections too.
gapon the widget spaces cards apart, not the rows inside them; the innerrow-gapis pinned to zero so the subgrid tracks meet. - Subgrid is required. Every current browser supports it, but a very old one falls back to a plain grid: the cards still lay out, they simply stop aligning internally. Nothing breaks.
-
The
cardsproperty does nothing. It is declared on the controller and never read. Cards are markup.
Usage guidance
Reach for cnc-cards when the cards have a repeating internal structure that ought
to line up — a product grid, a pricing table, a set of dashboard tiles. When the items are a
single block each, an ordinary Tailwind grid says the same thing with less to explain. For a
list rather than a grid, use cnc-list; for tiles the user can move and resize,
cnc-grid-stack; and for equal-sized viewports that must fill a fixed box,
cnc-autolayout.