Stop Flex and Grid Items Getting Cut Off with Tailwind v4 Safe Alignment

Tailwind safe alignment stops centered flex and grid items being clipped. Use justify-center-safe and items-center-safe to fall back to start on overflow.

Steven Richardson
Steven Richardson
· 7 min read

I shipped a horizontally scrolling filter bar last month. On my 27" monitor it was a neat centered row of chips. On a 375px phone, the first two chips were gone — not off to the right where you could scroll to them, gone off the left edge with no way back. The culprit was justify-center, and the fix was five characters: Tailwind safe alignment turns that class into justify-center-safe.

Why justify-center hides content you cannot scroll to#

A scroll container only creates scrollable overflow in the end direction. Content that spills past the start edge is unreachable — there is no negative scroll position to take you there.

justify-content: center distributes leftover space equally on both sides. When the leftover space is negative, it still splits it equally, which means half your overflow goes out the end edge (scrollable, fine) and half goes out the start edge (gone).

Here is the broken toolbar:

<!-- Looks centered on desktop, eats its first items on mobile -->
<div class="flex justify-center gap-2 overflow-x-auto p-4">
  <button class="shrink-0 rounded-full bg-zinc-100 px-4 py-2">All</button>
  <button class="shrink-0 rounded-full bg-zinc-100 px-4 py-2">Published</button>
  <button class="shrink-0 rounded-full bg-zinc-100 px-4 py-2">Scheduled</button>
  <button class="shrink-0 rounded-full bg-zinc-100 px-4 py-2">Awaiting review</button>
  <button class="shrink-0 rounded-full bg-zinc-100 px-4 py-2">Archived</button>
</div>

Drag the scrollbar all the way left and "All" is still nowhere. It is rendered, it is in the accessibility tree, keyboard focus will even scroll to it — but a touch user swiping the row never sees it. If you have built a snap-scrolling carousel with Tailwind v4, you have met the same failure mode: centering and horizontal scrolling do not mix by default.

What the CSS safe alignment keyword actually does#

safe is an overflow-alignment keyword from CSS Box Alignment Level 3. It sits in front of the alignment value:

.toolbar {
  justify-content: safe center;
}

Read it as a conditional: center this, unless centering would overflow, in which case align to start. While the content fits, safe center is byte-for-byte identical to center. The moment it stops fitting, the browser silently switches to start and pushes 100% of the overflow to the end edge — where the scroll container can actually reach it.

Its sibling unsafe forces the requested alignment no matter what. Without either keyword you get the current behaviour: the alignment is honoured and the overflow lands wherever it lands.

safe is only meaningful with center and end / flex-end. There is no safe start, because start alignment can never push content into the unreachable direction in the first place.

Tailwind safe alignment utilities and what they compile to#

Tailwind exposes safe alignment across every box-alignment property. The important detail: safe is a suffix, not an infix. It goes on the end of the class name.

Class CSS
justify-center-safe justify-content: safe center;
justify-end-safe justify-content: safe flex-end;
items-center-safe align-items: safe center;
items-end-safe align-items: safe flex-end;
self-center-safe align-self: safe center;
self-end-safe align-self: safe flex-end;
justify-items-center-safe justify-items: safe center;
justify-items-end-safe justify-items: safe end;
justify-self-center-safe justify-self: safe center;
justify-self-end-safe justify-self: safe end;
place-content-center-safe place-content: safe center;
place-content-end-safe place-content: safe end;
place-items-center-safe place-items: safe center;
place-items-end-safe place-items: safe end;
place-self-center-safe place-self: safe center;
place-self-end-safe place-self: safe end;

These arrived in Tailwind v4.1, so anything still on v3 needs to move first — the official Tailwind v3 to v4 upgrade tool does most of that work for you.

The toolbar fix is a single class:

<!-- Centered while it fits, start-aligned and fully scrollable when it does not -->
<div class="flex justify-center-safe gap-2 overflow-x-auto p-4">
  <button class="shrink-0 rounded-full bg-zinc-100 px-4 py-2">All</button>
  <button class="shrink-0 rounded-full bg-zinc-100 px-4 py-2">Published</button>
  <button class="shrink-0 rounded-full bg-zinc-100 px-4 py-2">Scheduled</button>
  <button class="shrink-0 rounded-full bg-zinc-100 px-4 py-2">Awaiting review</button>
  <button class="shrink-0 rounded-full bg-zinc-100 px-4 py-2">Archived</button>
</div>

No media query, no container query, no JavaScript measuring widths on resize.

Safe alignment in grid layouts#

The same trap exists on the cross axis. A grid row with a fixed height and an oversized cell will centre that cell out of both edges:

<!-- items-center-safe: vertically centered until the cell is taller than the row -->
<div class="grid h-40 grid-cols-3 items-center-safe gap-4 overflow-y-auto">
  <div class="rounded bg-zinc-100 p-3">Short</div>
  <div class="rounded bg-zinc-100 p-3">
    A much longer block of content that outgrows the row height once it wraps
    onto several lines on a narrow screen.
  </div>
  <div class="rounded bg-zinc-100 p-3">Short</div>
</div>

For per-item control use self-center-safe on the child instead of items-center-safe on the container. If you are aligning nested grids, the same reasoning applies inside each track — worth reading alongside Tailwind v4 subgrid for aligning nested grids.

Where Tailwind safe alignment earns its keep#

I now reach for it in four places:

  • Horizontally scrolling tab bars, filter chips and toolbars. The canonical case. justify-center-safe on the flex container, shrink-0 on the children.
  • Modal action rows. justify-center-safe on a row of buttons that looks fine in English and overflows in German.
  • Table header cells. A centered header whose label is wider than its column pushes half the text under the previous column.
  • Anything user-sized. Content whose width you cannot predict — user-generated names, translated labels, an auto-growing textarea — is exactly where centering breaks and you will not catch it in review.

I default to justify-center-safe over justify-center on any container that also has overflow-x-auto. The behaviour is identical when there is room, so there is no reason not to.

Gotchas and Edge Cases#

The suffix order bites everyone once. justify-safe-center and items-safe-center are not classes. Tailwind puts the modifier last: justify-center-safe, items-center-safe. An unrecognised utility generates no CSS and throws no error, so you get the broken layout back with a class that looks right. If a safe utility appears to do nothing, grep the compiled stylesheet for it before you debug anything else.

align-content has no -safe utility. There is no content-center-safe. Use the shorthand, which sets both axes:

<div class="grid h-40 place-content-center-safe gap-4">...</div>

Or, if you only want the block axis, an arbitrary property (underscores stand in for spaces):

<div class="grid h-40 [align-content:safe_center]">...</div>

Unsupported browsers lose the centering entirely, not just the safety. justify-content: safe center is a single declaration. An engine that cannot parse safe discards the whole thing and falls back to the initial value — so old Safari gets normal, i.e. start-aligned, not centered. That is usually the degradation you wanted anyway. When centering is load-bearing, layer the declarations in a custom utility so the old value survives:

@utility justify-center-safely {
  justify-content: center; /* fallback for engines without safe alignment */
  justify-content: safe center; /* overrides the above where supported */
}

Support is good but not universal. Chrome and Edge 115+, Firefox 63+, Safari and iOS Safari 17.6+, Samsung Internet 23+ — around 88% of global traffic. Check your own analytics before treating it as a baseline.

It falls back to start, which is writing-mode relative. In an RTL layout start is the right edge. That is correct behaviour, but if you have hardcoded any left-side affordance (a fade mask, a scroll-left button) it will be on the wrong side.

You cannot see it working at your desk. Safe alignment is a no-op until something overflows. Test at 320px with the longest string in your translation files — the same discipline that catches mobile viewport-height bugs.

Wrapping Up#

Audit every container in your app that pairs a centering utility with overflow-x-auto or a fixed height, and swap justify-center for justify-center-safe. It costs nothing where the content fits and it stops a whole class of invisible mobile bugs.

From there, container queries let a component respond to the space it actually has rather than the viewport, and the snap-scrolling carousel build shows the rest of the horizontal-scroll toolkit these utilities pair with.

FAQ#

What does safe do in CSS alignment?

safe is an overflow-alignment keyword. Written in front of an alignment value — justify-content: safe center — it applies that alignment normally, but switches to start alignment the moment the content would overflow its container. The effect is that all overflow ends up on the end edge, where a scroll container can reach it, instead of being split across both edges.

Why does justify-center cut off my content?

Because center splits leftover space evenly even when that space is negative. Half the overflow goes past the end edge and half goes past the start edge. Browsers only create scrollable overflow in the end direction, so the start-side half is genuinely unreachable — you cannot scroll to it, and on touch devices there is no way to see it at all.

How do I use safe alignment in Tailwind?

Add -safe to the end of a center or end alignment utility. justify-center becomes justify-center-safe, items-center becomes items-center-safe, place-content-center becomes place-content-center-safe. It is a drop-in replacement — the rendered result is identical whenever the content fits, so there is no responsive variant to manage.

What is the difference between safe-center and center?

Nothing at all, until the content overflows. center keeps centering regardless and pushes half the overflow out of reach; safe center detects the overflow and falls back to start, keeping every item scrollable. Since the two behave identically in the non-overflow case, safe center is the safer default on any container that can scroll.

Do all browsers support safe alignment?

Not quite. Chrome and Edge support it from 115, Firefox from 63, and Safari and iOS Safari from 17.6 — roughly 88% of global traffic. Browsers that do not recognise safe discard the entire declaration rather than just the keyword, so they fall back to the property's initial value (start-aligned) rather than to plain centering. Declare justify-content: center immediately before the safe version if you need centering preserved on older engines.

Steven Richardson
Steven Richardson

CTO at Digitonic. Writing about Laravel, architecture, and the craft of leading software teams from the west coast of Scotland.