Loading placeholders, compose-first.
The primitive is a single brick - size it with classes exactly like
shadcn's skeleton, pick a shape with variant, and choose pulse,
shimmer or none for motion (shimmer is the premium sweep; both stand
still under prefers-reduced-motion):
<.skeleton variant="circle" class="size-12" />
<.skeleton variant="text" class="w-48" />
<.skeleton class="h-32 w-full" />skeleton_text/1 builds a realistic paragraph (varied, deterministic line
widths), and skeleton_group/1 is the accessibility wrapper: it announces
the loading state once (role="status", aria-busy, screen-reader label)
while the bricks inside stay decorative. Set animation on the group and
every skeleton inside follows; an explicit per-brick animation wins.
The legacy kind: layouts (:default, :image, :video, :text, :card,
:widget, :list, :testimonial) still render for backwards compatibility -
prefer composing the primitives.
Summary
Functions
The composable loading brick. Pass the legacy kind attr for the old prebuilt layouts.
The accessibility wrapper for a loading region. Announces once; the bricks inside stay decorative.
A realistic paragraph placeholder: line widths vary in a fixed pattern (deterministic, so LiveView re-renders never make the skeleton dance) and the last line runs short.
Functions
The composable loading brick. Pass the legacy kind attr for the old prebuilt layouts.
Attributes
variant(:string) - the brick shape: block (theme-radius rectangle), text (a rounded line with a sensible default height), circle (avatar). Defaults to"block". Must be one of"block","text", or"circle".animation(:string) - pulse (default), shimmer (a moving highlight sweep), or none. When unset, inherits from an enclosing skeleton_group. Defaults tonil. Must be one ofnil,"pulse","shimmer", or"none".kind(:atom) - LEGACY prebuilt layouts - prefer composing skeleton/skeleton_text/skeleton_group. Defaults tonil. Must be one ofnil,:default,:image,:video,:text,:card,:widget,:list, or:testimonial.class(:any) - size it here, e.g. class="h-4 w-48". Defaults tonil.- Global attributes are accepted.
The accessibility wrapper for a loading region. Announces once; the bricks inside stay decorative.
<.skeleton_group label="Loading posts" class="flex items-center gap-4">
<.skeleton variant="circle" class="size-12" />
<div class="flex-1 space-y-2">
<.skeleton variant="text" class="w-1/2" />
<.skeleton variant="text" class="w-full" />
</div>
</.skeleton_group>Attributes
label(:string) - what screen readers announce while the skeleton shows. Defaults to"Loading...".animation(:string) - cascades to every skeleton inside; a brick's own animation attr wins. Defaults tonil. Must be one ofnil,"pulse","shimmer", or"none".class(:any) - Defaults tonil.- Global attributes are accepted.
Slots
inner_block(required)
A realistic paragraph placeholder: line widths vary in a fixed pattern (deterministic, so LiveView re-renders never make the skeleton dance) and the last line runs short.
Attributes
lines(:integer) - number of text lines. Defaults to3.animation(:string) - see skeleton/1. Defaults tonil. Must be one ofnil,"pulse","shimmer", or"none".class(:any) - Defaults tonil.- Global attributes are accepted.