top of page

How to Add Skeleton Loaders in Wix Studio with CSS

When building web apps, loading states are often overlooked, but they can make or break the user experience. Instead of leaving visitors staring at a blank screen or a clunky spinner, modern apps use skeleton loaders — animated placeholders that give a preview of the page layout while content is being fetched.

In this tutorial, we’ll walk through how to implement skeleton loaders in Wix Studio using CSS and a bit of Velo code. You’ll also see how to handle error states gracefully with the same approach.



Why Skeleton Loaders?


Traditionally, developers used three states to handle data fetching in Wix:

  1. Loading State – A spinner or message while waiting for data.

  2. Success State – Data displays correctly.

  3. Error State – A message when something goes wrong.

While this approach works, it often feels clunky and requires extra UI elements. Skeleton loaders offer a cleaner alternative by reusing your existing design with a subtle shimmering animation.


Step 1: Set Up a Repeater in Wix Studio

Start with a blank Wix Studio site and add a repeater to display dynamic content. For this demo, imagine you’re building a staff directory. If you already have you're own repeater set up, just skip this part!

  1. Add a repeater with an image, name field, and button.

  2. Use mock data for now, structured like this:

const staff = [
  { _id: "1", name: "Jane Doe", image: "image1.jpg" },
  { _id: "2", name: "John Smith", image: "image2.jpg" },
  { _id: "3", name: "Alex Green", image: "image3.jpg" }
];

⚠️ Important: Each repeater item needs a unique _id.

Step 2: Populate the Repeater with Code

Inside your page code, connect the mock data to the repeater:

function populateStaffRepeater() {
  $w("#staffRepeater").onItemReady(($item, itemData) => {
    $item("#staffName").text = itemData.name;
    $item("#staffImage").src = itemData.image;
  });
  $w("#staffRepeater").data = staff;
}

Call the function when the page loads. At this point, your repeater displays mock staff data.

Step 3: Simulate Loading & Error States (Aka. the old way)

Instead of instantly loading data, let’s simulate real-world conditions:

function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function loadRepeater() {
  try {
    $w("#staffRepeater").collapse(); 
    await delay(2000); // simulate fetch time
    populateStaffRepeater();
    $w("#staffRepeater").expand();
  } catch (error) {
    $w("#errorMessage").text = "Error: " + error.message;
    $w("#errorMessage").expand();
  }
}

This shows a loader for a couple of seconds before displaying content (or an error).


Step 4: Add Skeleton Loader CSS

Now for the fun part: skeleton loaders!

Open your Global CSS in Wix Studio and paste this snippet:

.skeleton {
  position: relative;
}

/* Apply skeleton effect to children shapes */
.skeleton::before {
  content: '';
  display: block;
  background: linear-gradient(90deg, #eee 25%, #ddd 50%, #eee 75%);
  background-size: 200% 100%;
  animation: loading 1.4s infinite;
  border-radius: 4px;
  position: absolute;
  z-index: 2;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}

/* Animate skeleton */
@keyframes loading {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
  }

This creates the shimmering block animation you see in apps like Facebook or LinkedIn. You can play around with the CSS to fit your design needs.


Step 5: Apply Skeleton Classes with Velo Code

When the page enters loading state, apply the .skeleton class to elements inside your repeater:

function addSkeleton() {
  $w("#staffRepeater").forEachItem(($item) => {
    $item("#staffName").customClassList.add("skeleton");
    $item("#staffImage").customClassList.add("skeleton");
    $item("#readMoreButton").customClassList.add("skeleton");
  });
}

function removeSkeleton() {
  $w("#staffRepeater").forEachItem(($item) => {
    $item("#staffName").customClassList.remove("skeleton");
    $item("#staffImage").customClassList.remove("skeleton");
    $item("#readMoreButton").customClassList.remove("skeleton");
  });
}

Update your loadRepeater function so skeletons appear before data loads and disappear once it’s ready. (In the video tutorial we took a slightly different approach but both are fine!)


Step 6: Handle Error States with CSS

We can also use CSS for errors. Add this to your global stylesheet:

/* Error message */
.error::before {
  display: none;
}

.error::after {
  content: 'Failed to load content';
  color: #b00020;
  background: #ffe6e6;
  border: 1px solid #ffcccc;
  padding: 8px;
  border-radius: 4px;
  font-size: 14px;
  position: absolute;
  z-index: 3;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  white-space: nowrap;
}

Then in your catch block:

$w("#staffRepeater").customClassList.add("error");

This overlays a friendly error message directly on your repeater.


Final Result

  • While data loads, your repeater shows shimmering skeleton placeholders.

  • Once ready, the skeletons disappear and your real data displays.

  • If something goes wrong, an error message is styled in via CSS.

The result is a smoother, more modern experience without bulky extra elements.


Wrap-Up

Skeleton loaders in Wix Studio provide a simple yet powerful way to improve UX. Instead of complex UI swaps, you just:

  • Add CSS for skeleton shimmer

  • Toggle classes with Velo

  • Use error CSS for fallback messages

This approach is lightweight, scalable, and reusable across your site.

 
 
 

Comments


RESOURCES

Become part of a thriving community

CONTACT US

Let's Make Some Magic!

Have a project in mind? Question? Just want to say hi?

Get in touch, and let’s bring your vision to life!

CONTACT INFORMATION

WHAT IS THE NATURE OF INQUIRY?

WHAT IS THE NATURE OF YOUR INQUIRY?
bottom of page