Feedback

Skeleton

Decorative placeholder that reserves layout space while real content loads, as a single block or a group of lines or a card, with optional delayed appearance and a "Still loading" status.

import { Skeleton } from '@lostgradient/cinder';
feedbackloading
01

Overview

Reference usage

Animated placeholder shape that fills content areas while data is loading.

Usage

svelte
<script lang="ts">
  import { Skeleton } from '@lostgradient/cinder';
</script>

<Skeleton />

Lines and variants

lines stacks text bars, and the last bar is shorter unless you pass width. variant="card" draws a heading bar and the lines inside a bordered card. Both match the real layout, so the page does not shift when content arrives:

svelte
<script lang="ts">
  import { Skeleton } from '@lostgradient/cinder';
</script>

<Skeleton lines={4} />
<Skeleton variant="card" lines={3} />

Loading rules

Cinder's loading rules are timing rules, and Skeleton implements them so each view does not rebuild them:

  • Show nothing for the first 300 ms, so a fast load never flashes a placeholder (delay={300}).
  • Show the skeleton in the real layout until 10 seconds have passed.
  • After 10 seconds, add a "Still loading" status with a Cancel button (stillLoadingAfter={10000} and onCancel).
svelte
<script lang="ts">
  import { Skeleton } from '@lostgradient/cinder';

  let loading = $state(true);
</script>

{#if loading}
  <Skeleton lines={5} delay={300} stillLoadingAfter={10000} onCancel={() => (loading = false)} />
{/if}

Both timers start when the Skeleton mounts, so render it only while the request is pending and unmount it when the request settles. Unmounting clears the timers. stillLoadingAfter counts from mount, not from the end of delay. Without delay or stillLoadingAfter a Skeleton renders immediately and never shows a status, exactly as a plain block always has.

Live preview

Skeleton placeholders

02

When to use

Use when
  • Reserving the rough shape of incoming content during an initial fetch to avoid layout shift.
  • Indicating progressive load of cards, rows, or media tiles where the final shape is known.
Avoid when
  • Indicating indeterminate background work without a known target shape — use spinner.
  • Communicating that a view has no data at all — use empty-state.
03

Examples

Skeleton placeholders

Animated loading placeholders for text and avatars.

Lines and card

lines stacks text bars; variant="card" draws a heading bar and lines inside a card.

Loading rules

Nothing for 300 ms, the skeleton until 10 seconds, then Still loading with Cancel.

04

Props

Props for skeleton
Name
Type
Default
Description
width text CSS width value applied as an inline style on the skeleton block (e.g. '200px', '100%').
height text CSS height value applied as an inline style on the skeleton block (e.g. '1rem', '48px').
radius text CSS border-radius value applied as an inline style, overriding the default pill shape (e.g. '4px', '50%').
lines number 1 Number of text bars to stack. More than one renders a group, and the last bar is shorter unless width is set. Clamped to between 1 and 20.
variant 'row' | 'card' 'row' Shape of the group. 'row' stacks the bars directly; 'card' wraps a heading bar and the lines bars in a bordered card.
delay number 0 Milliseconds to wait after mounting before anything renders. A load that finishes inside the delay never flashes a placeholder. Use 300 for the Cinder loading rule.
stillLoadingAfter number Milliseconds after mounting at which a "Still loading" status replaces silence, with a Cancel button when onCancel is set. Counted from mount, not from the end of delay. Use 10000 for the Cinder loading rule. Omit to never show the status.
onCancel () => void Called when the Cancel button in the "Still loading" status is pressed. The button renders only when this is set.
stillLoadingLabel text 'Still loading…' Text of the "Still loading" status.
cancelLabel text 'Cancel' Label of the Cancel button in the "Still loading" status.