← All writing
3 min read

Keep the layout steady while it responds

Making room for loading states, changing labels, and images.

In this domain settings screen, the form appears before the list has loaded. For a second and a half, there’s nothing between the table headings and the input. Then the rows arrive and push the form down.

If I’m already moving toward the input, I have to follow it. The page looked ready to use, but it hadn’t finished deciding where everything belonged.

I’d like that form to stay where it is. Here are a few small examples of making room for what comes next.

No placeholders
DomainStatus
studio.designActive
notes.designActive
folio.designActive
With skeletons
DomainStatus
studio.designActive
notes.designActive
folio.designActive
Replay with a simulated 1.5 s delay. Watch the input below.

The skeleton gives the rows their space before the data arrives. It also tells me something is loading, which the blank table doesn’t make clear.

For this to work, the placeholders need to follow the dimensions of the loaded rows. I’d use the same row height, padding, and column layout for both states. The gray bars can be shorter than the text they represent; the space around them needs to hold.

A skeleton that’s half the height of the final content still leaves the form moving when the response arrives.

There’s a limit here, too. Three placeholder rows won’t reserve the right amount of space for every possible result. If the count is unknown, I still need to decide how that region should grow, or whether the form should sit above the list. The skeleton helps when its shape is a reasonable match for what follows.

Content width
Reserved width
Same states. Watch the right edge and the + beside it.

The same problem can happen inside a button. Replace a label with a small spinner and the button shrinks just after I click it. Nearby content may move with it.

I’d keep the button’s outer dimensions steady while its contents change. The spinner can sit in the middle of the space the label occupied.

That doesn’t have to mean hardcoding one width everywhere. The button can reserve room for its widest state, including translated labels and larger text. What matters is that a routine status update doesn’t unexpectedly resize the control.

No reserved space
A photograph of Iceland

A pause along the way. Some things are worth the detour.

Known aspect ratio
A photograph of Iceland

A pause along the way. Some things are worth the detour.

A simulated 1.5 s reveal, not a network measurement.

Images are another place where we can often make this decision ahead of time. If we know the image’s proportions, the browser can reserve its space before the file arrives.

The paragraph can start in its final position. The image fills the frame when it’s ready.

Image dimensions or an appropriate aspect ratio make this possible. The reserved proportions need to match the displayed image; an arbitrary placeholder can still leave a jump when it loads.

I’m finding it useful to look at these states together. While reviewing a component, I want to see what happens before the content arrives, while an action is running, and after it finishes.

For the domain table, the check is simple: replay the loading state and watch the form. It should still be where I was about to click.

Credits & inspiration

  1. Inspiration for the format: small, interactive comparisons alongside the text. 7 Practical Animation Tips, Emil Kowalski.