Skeleton
Skeleton is the shape-preserving loading placeholder.
Use it when the layout is already known but the real data has not arrived yet. A skeleton helps the screen feel stable because the user can see where content will appear, even before the text or image is ready.
Example
use fission::prelude::*;
let node = VStack {
spacing: Some(12.0),
children: vec![
Skeleton {
id: WidgetNodeId::explicit("profile_avatar_loading"),
width: Some(48.0),
height: Some(48.0),
circle: true,
animated: true,
}
.build(ctx, view),
Skeleton {
id: WidgetNodeId::explicit("profile_name_loading"),
width: Some(180.0),
height: Some(18.0),
circle: false,
animated: true,
}
.build(ctx, view),
],
}
.into_node();
This keeps the loading state close to the final layout instead of replacing everything with a generic spinner.
Field table
| Field | Type | Meaning | Notes / default behavior |
|---|---|---|---|
id | WidgetNodeId | Stable identity used for animation state. | Required. Give each skeleton a unique id. |
width | Option<f32> | Placeholder width. | Defaults to 100.0. |
height | Option<f32> | Placeholder height. | Defaults to 20.0. |
circle | bool | Whether to render the placeholder as a fully rounded shape. | Defaults to false. Useful for avatar placeholders. |
animated | bool | Whether the placeholder should pulse in opacity. | Defaults to true. |
User experience guidance
A skeleton is best when you know the final shape of the content. If you have no idea what will load or when, a more generic loading treatment may be more honest.
The checked-in widget animates opacity when animated is true, so stable ids matter. If the id changes every build, the animation state cannot behave predictably.
Specific advice
Match the skeleton shape to the eventual content as closely as is practical. A loading state feels more polished when the placeholder predicts the final layout instead of using random bars everywhere.
Related
Spinner, CircularProgress, Card, and Avatar.