On this page Skeleton Skeleton

The m3e-skeleton component provides a loading placeholder surface with flexible shape variants and motion-based animations that communicate loading state while preserving layout stability. It mimics the layout of content while it's still loading, ensuring a smooth user experience during data fetching or rendering delays.

import "@m3e/web/skeleton";
Usage

This section outlines usage examples and configuration guidance for the components in this package.

Basic usage

Use the m3e-skeleton component to generate loading placeholders for any top-level slotted elements. The component creates an overlay shape for each node, matching its geometry while preserving the layout of the underlying content.

Use the loaded attribute to reveal loaded content.



Card Header
Card Content
Action
Card Footer
<m3e-skeleton>
  <m3e-card>
    <m3e-heading slot="header" variant="display" size="small">Card Header</m3e-heading>
    <div slot="content">Card Content</div>
    <div slot="actions">
      <m3e-button variant="filled">Action</m3e-button>
    </div>
    <div slot="footer">Card Footer</div>
  </m3e-card>
</m3e-skeleton>
Shape

Use the shape attribute to define the geometry applied to all top level slotted content. Each node receives a corresponding skeleton overlay that reflects the selected shape. The circular option produces a circle based on the element size. The rounded option applies the standard radius token used by most surfaces and controls. The square option renders with no radius for a sharp edge appearance. The auto option reads the actual border radius of the slotted element and mirrors it exactly, ensuring the skeleton aligns with cards, buttons, images, or any custom component without additional configuration.




<m3e-skeleton shape="circular">
  <div style="width: 100px; height: 100px"></div>
</m3e-skeleton>
<br />
<m3e-skeleton shape="rounded">
  <div style="width: 100px; height: 100px"></div>
</m3e-skeleton>
<br />
<m3e-skeleton shape="square">
  <div style="width: 100px; height: 100px"></div>
</m3e-skeleton>
<br />
<m3e-skeleton shape="auto">
  <div style="width: 100px; height: 100px; border-radius: 16px"></div>
</m3e-skeleton>
Animation

Use the animation attribute to control how the skeleton communicates loading progress. When enabled, the component applies motion across all top level slotted content to indicate that data is being fetched. The wave option renders a smooth directional sweep that suggests ongoing work. The pulse option applies a rhythmic fade in and fade out effect that draws attention without strong directional movement.




<m3e-skeleton shape="circular" animation="pulse">
  <div style="width: 100px; height: 100px"></div>
</m3e-skeleton>
<!-- Additional skeletons omitted for brevity -->

The none option disables motion and displays a static placeholder for environments that prefer reduced movement or for layouts that require a quiet loading state.




<m3e-skeleton shape="circular" animation="none">
  <div style="width: 100px; height: 100px"></div>
</m3e-skeleton>
<!-- Additional skeletons omitted for brevity -->
Accessibility

A skeleton's color uses the lowest perceptual contrast that remains reliably visible, keeping the placeholder subtle and non-intrusive.

Skeletons are purely visual placeholders and should not expose any semantic role or announce themselves to assistive technologies. The m3e-skeleton element remains neutral and should have no role, no aria-label, no aria-live, and no aria-busy. Loading state should be communicated by applying aria-busy="true" to a parenting container, ensuring screen readers understand that content is loading without being interrupted by decorative placeholders.

Native module support

The @m3e/web package uses JavaScript Modules. To use it directly in a browser without a bundler, use a module script similar to the following.

<script type="module" src="/node_modules/@m3e/web/dist/skeleton.js"></script>

In addition, you must use an import map to include dependencies.

<script type="importmap">
  {
    "imports": {
      "tslib": "https://cdn.jsdelivr.net/npm/tslib@2.8.1/+esm",
      "lit": "https://cdn.jsdelivr.net/npm/lit@3.3.0/+esm",
      "lit/": "https://cdn.jsdelivr.net/npm/lit@3.3.0/",
      "lit-html": "https://cdn.jsdelivr.net/npm/lit-html@3.3.0/+esm",
      "lit-html/directive.js": "https://cdn.jsdelivr.net/npm/lit-html@3.3.0/directive.js",
      "@lit/reactive-element": "https://cdn.jsdelivr.net/npm/@lit/reactive-element@2.0.4/+esm",
      "@lit/reactive-element/": "https://cdn.jsdelivr.net/npm/@lit/reactive-element@2.0.4/",
      "@m3e/web/core": "/node_modules/@m3e/web/dist/core.js",
      "@m3e/web/core/anchoring": "/node_modules/@m3e/web/dist/core-anchoring.js"
    }
  }
</script>

For production builds, use the minified files to ensure optimal load performance.

API

The @m3e/web package includes a Custom Elements Manifest (custom-elements.json), which documents the properties, attributes, slots, events and CSS custom properties of each component.

You can explore the API below, or integrate the manifest into your own tooling.