Building a Non-Collapsing Loading Button with CSS Grid

A common challenge in web development is maintaining consistent button dimensions during loading states. When a button transitions from showing text to displaying a loading spinner, it often causes layout shifts that can disrupt the user experience. Let's solve this using CSS Grid.

Live Demo

The Problem

Traditional approaches to loading states often involve replacing button content with a spinner, which can cause the button to collapse or expand. This creates a jarring user experience and can lead to layout shifts in your UI.

The Solution

We'll use CSS Grid to create a stable button that maintains its dimensions during state changes. The key is to layer the text and spinner in the same grid area.

Implementation Steps

  1. Grid Container Setup

    Transform the button into a grid container with a single named area:

    button {
      display: grid;
      grid-template-areas: "stack";
    }
  2. Element Placement

    Place both text and spinner in the same grid area:

    button .spinner,
    button .text {
      grid-area: stack;
    }
  3. State Management

    Use opacity transitions for smooth state changes:

    button.loading .text {
      opacity: 0;
    }
    
    button.loading .spinner {
      opacity: 1;
    }

Key Benefits

Browser Support

This solution uses CSS Grid, which has excellent browser support (95%+ global usage). For older browsers, you might want to provide a fallback that maintains button dimensions using fixed widths or min-width properties.

Check out this video from Wes Bos for a walkthrough of this.