Prevent Button Shrink on Load - A Better UI Pattern with Tailwind CSS

5 Jul 2025 • 8 mins read

Article Cover

When creating loading buttons in React, the common approach of swapping text with a loader using conditional rendering often causes unwanted layout shifts. This article introduces a cleaner solution: layering both the loader and the text using CSS grid and toggling their visibility instead of replacing them. This method ensures the button retains its size, resulting in a smoother, more polished UI—especially when using Tailwind CSS.

When building buttons with a loading state in React, a common pattern many developers use is conditional rendering:

{pending ? <Loader /> : "Submit"}

At first glance, this works. But there’s a subtle (and frustrating) UI issue: The button shrinks or changes size when toggling between the text and the loader. This causes layout shift and makes your interface feel unpolished.

The Problem

Imagine you have a button like this:

<button>
  {pending ? <Loader /> : "Submit"}
</button>

When pending becomes `true, the text disappears and the loader appears. But unless your loader has exactly the same width as your button text, the button will resize — often noticeably.

Button shrinking

The Solution - Layer, Don't Swap

Instead of conditionally rendering one or the other, we can stack both elements using CSS grid and control visibility. This keeps the layout intact and provides a smooth experience.

Here’s how to do it with Tailwind CSS:

<button className="grid [grid-template-areas:'stack']">
  <Loader
    className={`[grid-area:stack] m-auto ${pending ? 'visible' : 'invisible'}`}
  />
  <span
    className={`[grid-area:stack] ${pending ? 'invisible' : 'visible'}`}
  >
    Submit
  </span>
</button>

Why this works:

  • Both the text and loader are always present in the DOM
  • They're positioned in the exact same spot using grid area stack
  • We just toggle their visibility, so the button dimensions stay fixed

Wrap Up

A smoother UI doesn’t always require complex code; sometimes, it’s as simple as switching from conditional rendering to toggling visibility.