CategoryProduct design
Loading and empty states: where interfaces tend to lie
A loading state and an empty state are what a person sees while the data hasn’t arrived or doesn’t exist. They aren’t decoration. They are where an interface most often misleads, because a placeholder can promise a shape that never arrives and a spinner can imply progress nobody measured.
Why the wait needs a signal, and when the signal hurts
IBM’s Carbon Design System states that loading strategies assure users their request is in progress, and that skeleton states and other loading indicators can create the illusion of shorter load times. The same loading pattern limits skeleton states to a few seconds on screen.
A signal earns its place when the wait is long enough to be noticed. The Nielsen Norman Group response time limits place that point at one tenth of a second, below which no special feedback is needed. Below that point the indicator appears and disappears inside a few frames, and the movement reads as a flicker rather than as information. The Nielsen Norman Group notes in Skeleton Screens 101 that animated skeletons can be distracting or annoying, and can create accessibility problems for some users.
The Carbon loading pattern separates the cases by what is knowable. A loading indicator signals that loading is occurring and, unlike a progress bar, gives no indication of progress. A progress bar is the right control when the system can measure the work remaining.
So the short wait gets no signal, the unknown wait gets an indicator, and the measurable wait gets a progress bar. A wait long enough to be measured in minutes also needs an estimate of when it will finish, per the Nielsen Norman Group guidance on progress indicators.
Skeleton against indicator: what each one promises
A skeleton screen is a simplified version of the component that will replace it. The Nielsen Norman Group describes it as a wireframe that mimics the layout of the page and helps the person build a mental model of what will appear. The same text scopes the skeleton to full-page loads, while the Carbon pattern scopes it to the component.
An indicator promises only that something is happening. A skeleton promises a shape, a hierarchy and an order. When the real content arrives in a different shape, the swap moves elements the person had already located, and that movement reads as a defect.
The Carbon loading pattern restricts where skeletons belong. They fit container-based components such as tiles and structured lists, and data-based components such as tables and cards. Action components such as buttons, inputs, checkboxes and toggles don’t need a skeleton state. Toasts, overflow menus, dropdown items, modals and loaders shouldn’t be represented by one.
What the skeleton does to layout shift
Google defines Cumulative Layout Shift as the largest burst of layout shift scores during the life of a page, measured at the 75th percentile and split between mobile and desktop. A good score is 0.1 or less, and a poor score is above 0.25.
A burst, called a session window, groups shifts that occur less than one second apart, with a maximum window of five seconds. Google lists the usual causes as images or videos with unknown dimensions, fonts that render at a different size than the fallback, and third-party widgets that resize themselves.
A skeleton adds a shift when its box doesn’t match the box of the element that replaces it. The fix is arithmetic rather than aesthetic. The placeholder and the final element share the same width, height and position, so the swap replaces pixels instead of moving them.
The same Google article on layout shift warns that the problem hides in development, where test images sit in the browser cache and local API calls answer faster than production ones. A shift that never appears on a developer machine is normal on a phone.
The stakes are concrete. Google’s article records that a sudden shift can make a person click the wrong link or button, and can lead someone to confirm an order they meant to cancel.
The four states, and the two that get skipped
Loading, empty, error and success are four states with four different jobs. Most teams design success and the loading spinner, and leave empty and error to whatever the framework renders by default. The Nielsen Norman Group notes that the default of an empty space is to simply remain empty.
Empty isn’t error, and the two are the most common merge. Empty means the request succeeded and returned nothing. Error means the request didn’t succeed. The treatments differ in the copy and in the action offered.
The Carbon empty states pattern names three families of empty state. No data covers first use. User action covers no results and confirmation of a completed process. Error management covers permissions, system issues and missing configuration.
Success is a state as well. After an action completes, the interface confirms it, or the person repeats the action to check whether it worked.
What a screen reader announces in each state
The W3C specification for WAI-ARIA 1.2 defines aria-busy as a sign that an element is being modified. Assistive technologies may wait until the changes finish before exposing them to the user. That is the mechanism for a container that data will replace.
For text that appears without a page reload, the specification defines aria-live as an indication that an element will be updated. The value describes which updates the user agents and assistive technologies can expect.
With a polite value, the specification says assistive technologies should announce updates at the next graceful opportunity, such as the end of the current sentence or when the person pauses typing. With an assertive value, they should notify the user immediately.
The specification adds that an interruption may disorient the person, so assertive belongs to the error that blocks the task and not to the routine update.
The alert role carries an implicit assertive live value and an implicit atomic value of true, according to the specification. Atomic decides whether the whole region is read or only the node that changed. The W3C publishes the WAI-ARIA Authoring Practices as the patterns built on that specification.
The Carbon loading pattern states the accessibility requirement in one line. A screen reader should notify a user if an application is loading, busy, gets stuck or fails.
Announcing too much is the other failure. A polite region that re-renders ten times queues ten messages the person can’t stop. An assertive burst loses the earlier messages, because the specification allows user agents to clear queued changes when an assertive change arrives.
An empty state is static text and is announced when the reader reaches it. If it appears after a search, it needs a live region or a focus move, or the person hears nothing and waits for a result that won’t come.
How to build the empty state with an action
Carbon’s anatomy for an empty state lists an optional non-interactive image, a short title, a body that explains the next action, a primary action, and an optional secondary link.
The same empty states pattern recommends writing the title as a positive statement. Its example is that “Start by adding data assets” reads better than “You don’t have any data assets”. The pattern also warns that empty states are treated as an afterthought and that extra content carries a cognitive cost.
For a first use, the action creates the first record. For no results, the action loosens the filter, and the copy names the filter to change. For an error, the primary action retries and the secondary action reports.
A message with no action is a dead end. The state is finished when the person knows what happened and has one control that changes it.
How to verify before publishing
- Throttle the connection and watch the loading state appear. If it lasts less than a frame, remove it.
- Open a new account for the empty state, and run a search that matches nothing for the no-results state.
- Block the request or return a 500 to force the error state, and check that the retry works.
- Compare the skeleton box with the final element box. Different dimensions mean a shift is already scheduled.
- Measure CLS in the field at the 75th percentile, since Google documents that lab and field data differ.
- Run a screen reader over each state and count the messages. More than one message per action means the region is too talkative.
- Reach every action with the keyboard alone, and confirm the focus lands somewhere useful after the state changes.
- Confirm the error state appears after a timeout the person can tolerate, and not after one that feels like a freeze.
A state that only says there is no data leaves the person stuck, with no idea what to do. Name the four states, give each one a message and an action, and verify both with the network throttled and the reader on.


