DEV Community

Sachin Kasana
Sachin Kasana

Posted on • Originally published at sachinkasana.Medium on

I Replaced My Spinner with a Skeleton — And My UX Skyrocketed

I Replaced My Spinner with a Skeleton — And My UX Skyrocketed 🚀

Let’s be honest. Loading spinners are the default move when your app needs a second to breathe. But here’s the problem:

Spinners tell users something is happening_. Skeletons show users_ what’s coming.

spinner vs Skeleton

That tiny shift made a huge difference in my app’s user experience — and it took less than 10 minutes to implement.

😩 The Problem: Spinners Are Vague

A spinner feels like an empty elevator. You know you’re supposed to wait, but you have no idea for how long, where you’re going, or if it’s even working.

Case in Point: My Product Page

Here’s what I was doing:

{isLoading ? (
  <div className="spinner">Loading...</div>
) : (
  <ProductList products={data} />
)}
Enter fullscreen mode Exit fullscreen mode

While it technically worked, it offered no clue about what was loading. Users just stared at a circle going in circles. 😵‍💫

💡 The Fix: Skeleton Screens

Skeleton screens are UI placeholders shaped like the content they’re loading. Instead of showing nothing (or worse, a mystery spinner), they hint at what’s coming.

Here’s the improved version:

{isLoading ? (
  <div className="skeleton-grid">
    {Array(6).fill().map((_, i) => (
      <div className="skeleton-card" key={i}></div>
    ))}
  </div>
) : (
  <ProductList products={data} />
)}
Enter fullscreen mode Exit fullscreen mode

Tailwind-Style Skeleton Example:

<div className="bg-gray-200 h-40 w-full rounded-md animate-pulse"></div>
Enter fullscreen mode Exit fullscreen mode

This gave users something familiar to look at — a grid of loading placeholders that resembled product cards.

📈 What Actually Improved

After swapping out spinners for skeletons, we tracked key UX metrics:

fcp, spinner vs skeleton

Even though the backend/API speed didn’t change, the perception of speed improved dramatically.

🧰 Tools You Can Use

Want to do this fast? Here are some options:

1. React Loading Skeleton

npm install react-loading-skeleton

import Skeleton from 'react-loading-skeleton';
<Skeleton height={40} count={6} />
Enter fullscreen mode Exit fullscreen mode

2. Tailwind CSS Approach

No library needed:

<div className="h-4 w-3/4 bg-gray-300 rounded-md animate-pulse"></div>
Enter fullscreen mode Exit fullscreen mode

3. Custom CSS (if you’re old school)

.skeleton-card {
  background: #ddd;
  border-radius: 6px;
  height: 120px;
  animation: pulse 1.5s infinite;
}

@keyframes pulse {
  0% { opacity: 1; }
  50% { opacity: 0.4; }
  100% { opacity: 1; }
}
Enter fullscreen mode Exit fullscreen mode

🧠 Skeleton-First Design: A Better Default

Instead of loading nothing and waiting for the API to respond, I now design components to show skeletons first by default.

return (
  <div>
    {loading ? <SkeletonCard /> : <RealCard data={data} />}
  </div>
);
Enter fullscreen mode Exit fullscreen mode

It’s faster. More predictable. Less jarring.

🏁 TL;DR

  • Spinners are vague and frustrating.
  • Skeletons mimic layout and improve perceived speed.
  • One small swap = massive UX gains.
  • Try it in product pages, profile cards, dashboards — anywhere content loads.

“A 500ms spinner feels slow. A 500ms skeleton feels_ fast.”_

That one line of code might just be the UX upgrade your app needs.

🚀 If this post helped you rethink your loading UX, give it a few claps 👏 to help others discover it too!

💬 Got a UI trick or frontend hack that worked wonders for you? Drop it in the comments  — I’d love to learn from your experience.

🔔 Follow me here on Medium for more real-world frontend tips, performance wins, and dev insights.

👉 Connect with me on LinkedIn

🌐 Check out my projects at sachinkasana.dev

Top comments (0)