Skip to content
View as Markdown

Feedback

Skeleton

An animated placeholder shown while content loads.

Import

import { Skeleton } from "@loamui/core";

Usage

Every example has a CSStab. That’s the real, complete stylesheet for the component: plain, static CSS, with nothing running in the browser.

Basic lines

Stack skeletons to stand in for text while it loads. A bare Skeleton is one line tall (1lh) in the local typography, so it needs no height.

Circle + lines

An avatar-and-text placeholder for a list item.

Custom sizes

Use width and height for cards or thumbnails; shape comes from --loam-skeleton-radius or circle.

Wrap real content

Wrapped children size the box, so the placeholder matches the coming layout with no size props; flip visible when the data lands.

Guidance

When to use it

  • While loading content whose shape you already know: the skeleton mirrors the coming layout, so the swap to real content is a fill-in, not a rearrangement.
  • To hold the loaded content's space open and avoid layout shift while data arrives.

When not to

  • When you cannot predict what the loaded layout looks like. A skeleton that does not match what replaces it makes the swap more jarring than showing nothing, and perceived performance gets worse, not better. Use Loader.
  • For an operation that is not producing visible content in that spot (saving, deleting, background work). A skeleton promises content that never comes; use Loader next to the affected control.

Accessibility

  • The root renders aria-hidden: skeletons are never announced. Screen-reader users hear the real content when it arrives instead of a stream of meaningless placeholders.
  • Because skeletons are silent, announce the wait elsewhere if it needs announcing: a Loader (which renders role="status") or a visually hidden status message.
  • The moving shimmer is gated behind prefers-reduced-motion: no-preference. Reduced-motion users get the same placeholder with a static gradient, with no override needed because the motion is opt-in.
  • While visible, wrapped children are also unreachable by pointer and text selection (pointer-events: none, user-select: none), so nothing interactive is exposed before it is real.

How it works

Match the shape you are loading

Build the skeleton from the loaded UI's real dimensions: the avatar's diameter, the text's line heights, the thumbnail's radius. The entire benefit of a skeleton is that the eye has already parsed the layout before the content lands; a placeholder of a different shape spends that benefit and charges interest.

Swap in place with visible

Wrap the real content and flip visible to false when it is ready. The wrapped children size the placeholder themselves, so it mirrors the coming layout without declared dimensions; width and height exist for bare placeholders, where the absent content cannot be measured. While the skeleton is visible, children are hidden from pointer, selection and assistive tech, so nothing half-loaded leaks out.

Props

PropTypeDefaultDescription
widthnumber | string"100%"Inline size for a bare placeholder (number → px, or any CSS length). Wrapped content sizes itself.
heightnumber | string"1lh"Block size (number → px, or any CSS length).
circlebooleanRender as a circle (equal width/height, full radius).
visiblebooleantrueWhen false, render children instead of the placeholder.
childrenReactNodeReal content, shown once visible is false.
...othersHTMLAttributes<HTMLDivElement>All native <div> props are forwarded.

Custom properties

PropertySyntaxDefaultDescription
--loam-skeleton-radiusCSS lengthvar(--loam-radius-md)Corner rounding of the placeholder; set per instance or on a region.