Cluster utility
A single .cluster class that groups inline items — tags, buttons, icon pairs — with consistent gap and automatic wrapping.
Tags & chips — align: start
Buttons — align: center
Icon + text pairs — justify: space-between
Quick implementation
.cluster {
display: flex;
flex-wrap: wrap;
gap: var(--cluster-gap, 1rem);
align-items: center;
}
/* Optional alignment modifiers */
.cluster--start { justify-content: flex-start; }
.cluster--center { justify-content: center; }
.cluster--between { justify-content: space-between; }
Prompt this to your LLM
Includes role, constraints, two framework variants, and edge cases to handle.
You are a senior frontend engineer building reusable CSS layout utilities.
Goal: A .cluster utility class that arranges inline items — tags, buttons,
icon+text pairs — in a horizontal row that wraps naturally when the container
is too narrow, with consistent spacing controlled by a CSS custom property.
Technical constraints:
- Use display: flex; flex-wrap: wrap; align-items: center; on .cluster.
- Control spacing exclusively with gap: var(--cluster-gap, 1rem) — no margin
on child elements. The custom property lets callers override gap per instance
with style="--cluster-gap: 0.5rem;" without touching the stylesheet.
- Use oklch() for any colors — no hex or rgba values.
- Use CSS custom properties (var(--card), var(--text), etc.) for theming.
- Do not set a fixed width or height on .cluster itself — it should size to
its content and its container's available width.
Alignment modifiers (add as separate classes alongside .cluster):
A) .cluster--start → justify-content: flex-start
B) .cluster--center → justify-content: center
C) .cluster--between → justify-content: space-between
Framework variant (pick one):
A) Vanilla CSS utility classes, no JavaScript required.
B) React component — accept gap (string, default "1rem"), align
("start" | "center" | "between"), and children props; apply the correct
classes and pass gap as an inline CSS custom property.
Edge cases to handle:
- When items wrap to a second line the gap property applies equally in both
directions (row and column gap) — if you want different row and column gaps
use gap: <row-gap> <column-gap> shorthand.
- justify-content: space-between distributes remaining space between items;
on a single-item row this pushes nothing, so test with one item as well as
many.
- Children should not set their own margin — all spacing comes from the
parent gap so adding a new item never breaks existing spacing.
Return CSS only (or a React component if variant B is chosen).
Why flexbox wrap + gap replaced the negative-margin hack
Before gap worked in flexbox, the only way to get consistent spacing around wrapping inline items was the negative-margin technique: apply a negative margin to the flex container equal to half the desired gap, then a positive margin on every child. It worked, but it was fragile — the negative margin bled outside the container, breaking background colors and border radius on parent elements, and the math had to be updated in two places whenever the gap value changed.
gap in flexbox solves this cleanly. It adds space only between items, never at the outer edges, and it works in both the row and column directions when items wrap. There is no bleed, no extra selector for children, and no arithmetic. The cluster utility reduces the entire pattern to four lines of CSS plus a custom property for the gap value.
Browser support for gap in flexbox reached full coverage across all major engines in 2021 (Chrome 84, Firefox 63, Safari 14.1). As of 2026 it is safe to use without fallback in virtually all production environments.
How the cluster handles unknown item counts
The defining characteristic of the cluster pattern is that it places no constraints on how many items it contains. A tag list might have two items one day and twenty the next — the cluster does not need to know. flex-wrap: wrap lets the browser decide where to break the row based on available container width and the natural width of each item. Items that fit stay on the first row; items that don't wrap to a new row. The gap applies in both directions automatically.
This is different from a grid layout, which requires you to define columns in advance. A cluster is appropriate when items have variable, content-driven widths and the number of items is unpredictable — tags pulled from a CMS, buttons whose labels change with locale, or feature lists that grow over time. For fixed-column layouts where items should align to a strict grid, reach for CSS Grid instead.
The align-items: center declaration vertically centers items that have different heights — a common situation when mixing plain text chips with icon+text pairs or buttons with varying line heights. Remove it if items should align to their baseline or stretch to fill the row height.
Alignment options
The base .cluster class intentionally omits justify-content, letting the browser default to flex-start. Three modifier classes cover the most common needs:
.cluster--start explicitly sets justify-content: flex-start, which is useful when you want to be explicit in markup. .cluster--center centers the group of items within the container — good for action button rows below a form or a centered tag list on a card. .cluster--between uses justify-content: space-between, spreading the first item to the left edge and the last to the right, with remaining space distributed evenly between — useful for navigation bars or stat rows.
Because these are separate classes rather than inline styles, they are easy to apply conditionally in templates and easy to override in component stylesheets without specificity fights. You can also pass a custom gap per instance using the --cluster-gap custom property on the element's style attribute: style="--cluster-gap: 0.5rem;". The default of 1rem kicks in when no override is provided.