Skeleton
A Skeleton is a grey placeholder that shows where content will be while it loads. It pulses slowly. The user sees the layout of the screen before the data arrives, which feels faster than a spinner.

How to show a skeleton while content loads:
- Make the skeleton with the layout of the content: a circle for an avatar, lines for text, a block for a picture.
- Show the skeleton and hide the content.
- When the data is ready, hide the skeleton and show the content.
<ui:VisualElement name="cardSkeleton" style="flex-direction: row;">
<tb:Skeleton shape="Circle" />
<tb:Skeleton shape="Text" lines="3" style="flex-grow: 1; margin-left: 8px;" />
</ui:VisualElement>
<ui:VisualElement name="card" style="display: none;"> <!-- the content --> </ui:VisualElement>
var profile = await LoadProfileAsync();
card.Q<Label>("name").text = profile.Name;
root.Q("cardSkeleton").style.display = DisplayStyle.None;
card.style.display = DisplayStyle.Flex;
| Member | Description |
|---|---|
Shape (shape) |
Block (the default): a block that takes the size you give it. Text: lines of text. Circle: a 32 px circle. It sets the class tb-skeleton--block, --text or --circle. |
Lines (lines) |
The number of lines of a Text skeleton (default 1). The last of two or more lines is 60% wide. |
Animated (animated) |
On (the default): the skeleton pulses. Off: it is still. |
- The skeleton does not pulse in a workspace that has
AnimationsEnabledoff. - The pulse is one class (
tb-skeleton--dim) that changes each 0.8 s, with an opacity transition in USS. A skeleton that is not in a panel does no work. - A
Blockhas a minimum height of 12 px. Set its width and height in USS or withstyle.
Tips:
- Give a
Circlefor a large avatar the samewidthandheightas the avatar. - Keep the skeleton and the content the same size, so the layout does not jump when the content shows.
- Do not show a skeleton for a load that takes less than about 0.3 s. A flash of grey is worse than a short wait.
Styling
| Class | Element |
|---|---|
tb-skeleton |
The control. It has the opacity transition of 0.8 s for the pulse. |
tb-skeleton--block, --text, --circle |
The shape. A block and a circle have the --tb-color-border background; a circle is 32 px. |
tb-skeleton__line |
One line of a Text skeleton: 10 px high with a 3 px margin. |
tb-skeleton__line--last |
The last of two or more lines: 60% wide. |
tb-skeleton--dim |
Opacity 0.45. The control puts this class on and takes it off each 0.8 s. |
For a lighter placeholder and a softer pulse (the control changes the class each 0.8 s, so a transition longer than 0.8 s does not complete):
.tb-skeleton--block, .tb-skeleton--circle, .tb-skeleton__line { background-color: var(--tb-color-surface-hover); }
.tb-skeleton--dim { opacity: 0.7; }