Skip to content

Skeleton

A loading placeholder component for representing content that has not loaded yet. Use it to reduce layout shift and provide immediate visual structure while data is fetched.

Variants

Rectangle (Default)

PreviewCode
RTL
html
<ore-skeleton width="100%" height="1rem"></ore-skeleton> <ore-skeleton width="16rem" height="10rem"></ore-skeleton>

Circle

PreviewCode
RTL
html
<ore-skeleton variant="circle" size="sm"></ore-skeleton>
<ore-skeleton variant="circle" size="lg"></ore-skeleton>
<ore-skeleton variant="circle" width="3.5rem" height="3.5rem"></ore-skeleton>

Text

PreviewCode
RTL
html
<ore-skeleton variant="text" lines="3" width="100%"></ore-skeleton>
<ore-skeleton variant="text" lines="2" width="70%"></ore-skeleton>

Sizes

PreviewCode
RTL
html
<ore-skeleton size="sm" width="14rem"></ore-skeleton>
<ore-skeleton size="md" width="14rem"></ore-skeleton>
<ore-skeleton size="lg" width="14rem"></ore-skeleton>

Common Patterns

Card Placeholder

PreviewCode
RTL
html
<ore-card style="padding: var(--size-4); width: 20rem;">
  <ore-skeleton width="100%" height="10rem" style="margin-bottom: var(--size-4)"></ore-skeleton>
  <ore-skeleton variant="text" lines="3" width="100%"></ore-skeleton>
</ore-card>

List Item Placeholder

PreviewCode
RTL
html
<div style="display: grid; gap: var(--size-3); width: 100%; max-width: 28rem;">
  <div style="display: flex; align-items: center; gap: var(--size-3);">
    <ore-skeleton variant="circle" width="2.25rem" height="2.25rem"></ore-skeleton>
    <div style="flex: 1; display: grid; gap: var(--size-2);">
      <ore-skeleton variant="text" width="40%"></ore-skeleton>
      <ore-skeleton variant="text" width="70%"></ore-skeleton>
    </div>
  </div>
</div>

Animation Control

Use animated="false" for static placeholders.

PreviewCode
RTL
html
<ore-skeleton width="16rem" height="1rem"></ore-skeleton>
<ore-skeleton width="16rem" height="1rem" animated="false"></ore-skeleton>

Striped

Add striped to replace the shimmer with a diagonal stripe pattern. Useful for designers building page layouts — the high-contrast stripes make it immediately obvious where content placeholders are, without relying on animation.

PreviewCode
RTL
html
<ore-card padding="md" style="width: 280px;">
  <!-- Hero image area -->
  <ore-skeleton striped width="100%" height="160px" style="border-radius: 0; display: block;"></ore-skeleton>

  <ore-grid gap="md" style="margin-top: var(--size-4);">
    <!-- Avatar + author line -->
    <div style="display: flex; align-items: center; gap: var(--size-2);">
      <ore-skeleton striped variant="circle" width="2rem" height="2rem"></ore-skeleton>
      <ore-skeleton striped variant="text" width="6rem"></ore-skeleton>
    </div>

    <!-- Title -->
    <ore-skeleton striped width="90%" height="1.125rem"></ore-skeleton>

    <!-- Body text lines -->
    <ore-skeleton striped variant="text" lines="3" width="98%"></ore-skeleton>

    <!-- Action button -->
    <ore-skeleton striped width="7rem" height="2rem" style="border-radius: var(--rounded-lg);"></ore-skeleton>
  </ore-grid>
</ore-card>

The spacing between lines is adjustable via the --skeleton-stripe-size CSS custom property:

html
<ore-skeleton striped width="100%" height="2rem" style="--skeleton-stripe-size: 16px"></ore-skeleton>

API Reference

Attributes

AttributeTypeDefaultDescription
variant'rect' | 'circle' | 'text''rect'Visual shape preset
size'sm' | 'md' | 'lg'Height preset for rect/text; diameter for circle
widthstringWidth override (e.g. 12rem, 70%)
heightstringHeight override
radiusstringBorder-radius override
animatedbooleantrueSet animated="false" to disable shimmer
linesnumber1Number of text lines (variant="text")
stripedbooleanfalseDiagonal stripe pattern instead of shimmer

Parts

PartDescription
stackOuter container wrapping all bones
boneIndividual skeleton bone element

Events

This component does not emit custom events.

CSS Custom Properties

PropertyDescriptionDefault
--skeleton-bgBase colorvar(--color-contrast-200)
--skeleton-highlightShimmer highlight colorvar(--color-contrast-100)
--skeleton-radiusBorder radiusvar(--rounded-lg)
--skeleton-sizeCircle fallback sizevar(--size-10)
--skeleton-widthComponent width100%
--skeleton-heightComponent heightvar(--size-4)
--skeleton-line-gapGap between text linesvar(--size-2)
--skeleton-last-line-widthWidth of the final text line60%
--skeleton-durationShimmer animation duration1.6s
--skeleton-stripe-sizeSVG tile size controlling diagonal stripe density (striped)8px
--skeleton-stripe-colorColor of the diagonal lines and dashed border (striped)var(--color-contrast-400)

Performance

The shimmer animation is automatically paused when the element scrolls out of the viewport, using an IntersectionObserver. This prevents off-screen animations from consuming GPU resources.

Animation can also be disabled entirely with animated="false" — useful for static mockups or when the parent already shows a loading spinner.

Accessibility

Skeleton placeholders are decorative and non-interactive. Each bone is marked with aria-hidden="true" so screen readers skip over them entirely; no content is announced and no focusable roles or tab stops are exposed. The shimmer animation respects prefers-reduced-motion: reduce and is suppressed automatically when the user has requested reduced motion. In forced-colors environments the bone renders with ButtonFace background and ButtonText border for high-contrast visibility.

  • Progress for explicit operation progress states
  • Card for content containers commonly paired with placeholders
  • Text for loaded content replacing text skeleton lines