back

Why button labels should not change width while loading

One of the easiest ways to make a product feel less reliable is to let a loading button change width.

The user clicks Save changes, the label flips to Saving..., and suddenly the button shrinks or grows. The secondary action moves. The footer rhythm changes. The exact control that should feel most stable now looks like it is reflowing under pressure.

That is a small detail, but it lands at the worst possible moment. The user just committed an action and is waiting for confirmation that the product has it under control.

Why it feels wrong

Loading feedback is supposed to answer one question: did the action register?

If the button changes its outer footprint at the same time, it creates a second, unnecessary signal. Now the UI is not just busy. It is also moving around. That makes the state change feel less intentional and more accidental.

This matters most when the button lives in a tight layout:

In all of those places, button width is part of the layout, not just part of the label.

The better rule

If the action is the same button before and during loading, the button should usually keep the same outer width.

Change the content inside the shell. Do not let the shell resize itself.

That means:

The user still gets feedback. They just do not pay for it with layout shift.

A simple implementation

One of the cleanest patterns is to preserve width with an invisible copy of the widest label, then overlay the active content on top.

<button
  class="relative inline-grid min-h-11 place-items-center rounded-full bg-black px-4 py-2 text-sm font-medium text-white"
>
  <span class="invisible inline-flex items-center gap-2">Save changes</span>
  <span class="absolute inset-0 inline-flex items-center justify-center gap-2">
    <span
      class="h-3 w-3 animate-spin rounded-full border-2 border-white/35 border-t-white"
    ></span>
    Saving...
  </span>
</button>

The invisible span defines the width. The absolute layer handles the visible state. The button stays stable.

You can do the same thing with CSS grid, a fixed min-width, or two overlaid spans. The specific technique matters less than the rule: keep the outer dimensions calm.

Where this saves you

This is especially valuable when the loading state is short.

If the request takes 300 to 800 milliseconds, users might barely read the label change. What they will notice is the button jumping and the neighboring controls shifting with it.

A stable button gives you the best version of the interaction:

That is usually enough.

The rule of thumb

If the button is still the same button, treat loading as a content swap, not a layout change.

That one habit makes button loading states feel much more production-ready.