A lightweight Reactive Web UI block that displays animated placeholder shapes (the "shimmer" effect) while your screen or data is loading — instead of a blank area or a spinner.
Platform: OutSystems 11 (O11) · Type: Reactive Web · Curation target: Community / Trusted
Skeleton Loader gives your users a sense that content is on its way. Rather than showing an empty screen or a generic spinner while data loads, you show grey placeholder shapes that mimic the layout of the real content, with a soft animated shine sweeping across them.
Skeleton Loader
It is built entirely with CSS and a small amount of client-side logic — no integrations, no external services, no configuration required to get started. Drop the block on a screen, bind one boolean, and you have a working loading state.
osl-
Note: This component is designed for Reactive Web. It is not intended for Traditional Web or Mobile (though the CSS technique can be adapted).
.oap
The Skeleton block is now available in your widget toolbox under the producer module.
Skeleton
The minimum setup is three things: drop the block, put your real content inside it, and bind one boolean.
True
False
Loading
Skeleton IsLoading = not MyDataAction.Done // True while loading Type = Entities.SkeletonType.Text Lines = 3 └── [your real content here]
While IsLoading is True, users see the shimmer placeholders. When it flips to False, your real content appears in their place.
IsLoading
Type
Text
Lines
3
Width
"200px"
"50%"
Height
"40px"
The block exposes a single content area (Content) where you place the real UI that should appear once loading completes. You only ever fill this once — it is not per-type.
Content
The Type input accepts values from the SkeletonType static entity:
List
Table
Card
Avatar
Lines controls how many rows render for Text, List, and Table. It has no effect on Card or Avatar, which are single fixed layouts.
All placeholder shapes use the base class osl-skeleton (which carries the shimmer animation) plus one shape class. If you want to restyle the component in your own app, override these classes in your app theme.
osl-skeleton
osl-text
osl-list-row
osl-table-row
osl-card
osl-avatar
Each shape always combines two classes, e.g. osl-skeleton osl-text.
osl-skeleton osl-text
Because the styles are plain CSS classes, you can override them from your consuming app's theme. Common tweaks:
Change the placeholder colour — override the base class:
.osl-skeleton { background: linear-gradient(90deg, #d4d4d8 25%, #e4e4e7 50%, #d4d4d8 75%); background-size: 200% 100%; }
Slow down or speed up the shimmer — override the animation duration:
.osl-skeleton { animation-duration: 2.2s; }
Adjust a single instance's size — use the Width / Height inputs instead of CSS (no stylesheet edits needed).
The component respects the operating-system "reduce motion" preference. When a user has enabled reduced motion, the shimmer animation is disabled and the placeholders show as static grey shapes — still a valid, non-distracting loading indicator. No configuration is required for this; it works automatically.
There are two ideas behind the component:
The shimmer is a CSS trick. Each placeholder has a wide gradient background (twice the element width) with a bright band in the middle. A keyframe animation slides the gradient's position back and forth, so the bright band sweeps across a stationary element. This is cheap for the browser because only the background position moves.
The repeating rows (for Text, List, and Table) come from a small client-side list. On initialize, the block builds a list containing Lines items, and a List widget renders one placeholder row per item. The item values are never read — only the count matters, since every row is identical.
The placeholders show but never disappear.Your IsLoading binding is staying True. Make sure it is tied to the loading status of your data source and flips to False when the data arrives.
The real content never shows.Confirm you placed your content inside the block's content area, and that IsLoading reaches False.
No shimmer animation, just static grey.This is expected if the user (or your test machine) has "reduce motion" enabled in OS settings. It is the accessibility behaviour, not a bug.
The number of lines doesn't change.Lines only applies to Text, List, and Table types. Card and Avatar are fixed layouts.
Styles look wrong / classes clash with my app.All classes are prefixed osl-. If you have your own classes with the same names, rename yours or scope the override.
For questions or issues, use the component's Support tab on its Forge listing. When reporting a problem, include your OutSystems version and a short description of how you configured the block (Type, Lines, and how IsLoading is bound).
Published on the OutSystems Forge as open, reusable code. You are free to use and adapt it in your OutSystems projects.