Skip to content
Components
/
Skeleton
Dark

Skeleton

Skeleton holds the shape of content while it loads, so the screen does not jump when it arrives.

Preview

A placeholder that holds the shape of what is coming, so the screen does not jump when the data lands. For lists and cards this beats a spinner.

_Skeleton List Row, repeated three times
360 x 72, circle 40, lines at gap 8, pulse 480ms

One row is a 40 circle, a line that fills the rest and a short line under it, all breathing together. The description says to stack three to five while data loads. The pulse runs 480ms on a linear curve, the timing the file names motion/skeleton/pulse.

Types

Three shapes and nothing else. No text, no icons, no content of any kind.

Line, Circle and Block
200 x 12, 40 x 40, 200 x 120

Line and Circle are both radius full, so a 12 tall line is a stadium and a 40 square is a disc. Block is the only one on a real radius token, so it reads as a card rather than a pill. Every size here is a default meant to be resized on the instance.

Pulse

Two variants that are the two ends of one breath. Held still here so you can see both.

Pulse 1 then Pulse 2, at Line, Circle and Block
bg/sub-200 to bg/soft-100

Pulse is a timeline, not a state. Both ends move the same way in either theme: light runs #D1D1D6 down to #E9E9EA, dark #636366 down to #48484A, so it always breathes from more contrast to less, never lighter to darker. In code, animate between two colours and alternate.

Properties

Two axes, six variants, and one ready made row beside them.

Property
Type
Default
Type
Block | Circle | Line
Line
Pulse
1 | 2
1
Component
Variants
Size
Skeleton
6, Type crossed with Pulse
200 x 12, 40 x 40, 200 x 120
_Skeleton List Row
not a set, no properties
360 x 72 at radius 4

The file describes this row as matching the List component. It does not. List is 340 by 76 at radius 24, gap 12, tile at radius 12, 224 of content. This is 360 by 72 at radius 4, gap 16, circle at radius full, 272 of content. Six numbers, none shared, so a stack of these does not hold the shape of the list. That radius 4 is also the one raw value on the page.

Tokens

Two greys and one piece of motion. That is the whole component.

Token
Light
Dark
Applied to
bg/sub-200
#D1D1D6
#636366
Pulse 1, the stronger end of the breath
bg/soft-100
#E9E9EA
#48484A
Pulse 2, the weaker end
Motion token
Resolves to
Value
motion/skeleton/pulse/duration
motion/duration/slower
480ms
motion/skeleton/pulse/easing
motion/easing/linear
cubic-bezier(0, 0, 1, 1)

Linear is right here and unusual everywhere else in the system: a breath that eases reads as a thing being tapped, not a thing waiting. Neither grey is a semantic loading token. They are the background tokens used for dividers and empty states, so a skeleton on bg/soft-100 loses one end of its pulse.

Guidelines

Do

Repeat the row and let it hold the shape of the list underneath. Three to five is the range the file suggests, and nothing jumps when the data arrives.

Don't

Do not stand one grey block in for a list. It promises a shape the content will not have, so the layout jumps anyway and it says less than a spinner would.

Reach for it when the layout is known and the wait is short: lists, cards, a profile header. Match the skeleton to the real thing and resize the instance rather than accept the defaults. Do not skeleton a whole screen; a page of grey is harder to read than one spinner. Cap it: past about ten seconds the honest thing on screen is an error state.