Skip to main content

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

FieldTypeMeaningNotes / default behavior
idWidgetNodeIdStable identity used for animation state.Required. Give each skeleton a unique id.
widthOption<f32>Placeholder width.Defaults to 100.0.
heightOption<f32>Placeholder height.Defaults to 20.0.
circleboolWhether to render the placeholder as a fully rounded shape.Defaults to false. Useful for avatar placeholders.
animatedboolWhether 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.

Spinner, CircularProgress, Card, and Avatar.