DEV Community

Olebogeng Mbedzi
Olebogeng Mbedzi

Posted on

Stop Maintaining Manual Skeletons in React

If you've built a React application recently, you've likely implemented "Skeleton Screens": those gray, pulsating boxes that signify content is loading.

They provide a great user experience, but a terrible developer experience.

The Problem: The "Twin Component" Trap

To implement a skeleton correctly, you typically create a separate component (e.g., <UserCardSkeleton />) that visually mimics your real component.

// The Real Component
const UserCard = ({ user }) => (
  <div className="p-4 rounded-xl border flex gap-4">
    <img src={user.avatar} className="w-12 h-12 rounded-full" />
    <div>
      <h2 className="text-lg font-bold">{user.name}</h2>
      <p className="text-gray-500">{user.role}</p>
    </div>
  </div>
);

// The Skeleton (The "Twin")
const UserCardSkeleton = () => (
  <div className="p-4 rounded-xl border flex gap-4">
    <div className="w-12 h-12 rounded-full bg-gray-200 animate-pulse" />
    <div>
      <div className="h-4 w-32 bg-gray-200 rounded mb-2 animate-pulse" />
      <div className="h-3 w-24 bg-gray-200 rounded animate-pulse" />
    </div>
  </div>
);
Enter fullscreen mode Exit fullscreen mode

This works fine... until you change the design.

Scenario: You decide to move the avatar to the right side.
Result: You update <UserCard />. But if you forget to open <UserCardSkeleton />, your users see a jarring "layout shift".

You are effectively maintaining two UIs for every one component.

The Solution: Runtime DOM Measurement

What if the code could just look at our component and figure it out?

I built a library called shimmer-from-structure to do exactly that.

How it works

Instead of creating a skeleton, you wrap your real component in a <Shimmer> provider and pass it some mock data.

import { Shimmer } from 'shimmer-from-structure';

// 1. Define loading data structure
const userTemplate = {
  name: 'Loading Name...',
  role: 'Loading...',
  avatar: '/placeholder.png'
};

function Option() {
  return (
    // 2. Wrap your component
    <Shimmer 
      loading={isLoading} 
      templateProps={{ user: userTemplate }}
    >
      {/* 3. Render your REAL component */}
      <UserCard user={user || userTemplate} />
    </Shimmer>
  );
}
Enter fullscreen mode Exit fullscreen mode

When loading={true}:

  1. The library renders your UserCard with transparent text.
  2. It uses useLayoutEffect to measure the DOM geometry.
  3. It finds every img, text, and button node.
  4. It overlays a pixel-perfect shimmer animation.

Why this is better

  1. Zero Maintenance: If you move the avatar to the right, the shimmer automatically moves to the right.
  2. Pixel Perfect: The skeleton matches the exact height/width of your text content.
  3. Visual Stability: It preserves container backgrounds and borders.

Try it out

You can install it from NPM:
npm install shimmer-from-structure

Repo: https://github.com/darula-hpp/shimmer-from-structure

I'd love to hear your feedback in the comments! 👇

Top comments (3)

Collapse
 
art_light profile image
Art light

This is a solid take on eliminating the “twin component” anti-pattern—deriving skeletons from the real DOM is a much more scalable mental model. Using runtime measurement to guarantee layout parity is a smart trade-off, especially for complex, frequently changing UIs where manual skeletons inevitably drift.

Collapse
 
olebogengmbedzi profile image
Olebogeng Mbedzi

Thanks a lot for your comment, Hope you use it in your next project.

Collapse
 
art_light profile image
Art light

Thanks very very much😉