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
-
Grid Container Setup
Transform the button into a grid container with a single named area:
button { display: grid; grid-template-areas: "stack"; }
-
Element Placement
Place both text and spinner in the same grid area:
button .spinner, button .text { grid-area: stack; }
-
State Management
Use opacity transitions for smooth state changes:
button.loading .text { opacity: 0; } button.loading .spinner { opacity: 1; }
Key Benefits
- No layout shifts during state changes
- Smooth transitions between states
- Maintains accessibility with proper ARIA attributes
- Works with any button content length
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.