md-skeleton spec card
Identity · when to use / when NOT · decision cues · behavioural contract · do/don't · anti-patterns · full API. Paste into your agent when you're implementing with this component.
A content-shaped loading placeholder. Text lines, rectangles, rounded blocks or circles, with pulse or wave animation — used to reserve the layout while data loads so nothing jumps when it arrives.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: flex; gap: 16px; align-items: flex-start; width: 100%;">
<md-skeleton variant="circular" width="40px" height="40px" announce="false"></md-skeleton>
<md-skeleton variant="text" lines="3" full-width announce="false"></md-skeleton>
</div>import { MdSkeleton } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'flex', gap: '16px', alignItems: 'flex-start', width: '100%' }}>
<MdSkeleton variant="circular" width="40px" height="40px" announce="false"></MdSkeleton>
<MdSkeleton variant="text" lines="3" fullWidth announce="false"></MdSkeleton>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display: flex; gap: 16px; align-items: flex-start; width: 100%;">
<md-skeleton variant="circular" width="40px" height="40px" announce="false"></md-skeleton>
<md-skeleton variant="text" lines="3" full-width announce="false"></md-skeleton>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display: flex; gap: 16px; align-items: flex-start; width: 100%;">
<md-skeleton variant="circular" width="40px" height="40px" announce="false"></md-skeleton>
<md-skeleton variant="text" lines="3" full-width announce="false"></md-skeleton>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display: flex; gap: 16px; align-items: flex-start; width: 100%;">
<md-skeleton variant="circular" width="40px" height="40px" announce="false"></md-skeleton>
<md-skeleton variant="text" lines="3" full-width announce="false"></md-skeleton>
</div>
Already installed? See the
Installation guide for one-time package setup
(core + tokens, fonts). Each tab below shows two patterns for using
md-skeleton in your project: Option A registers every AWC UI
component at once (simplest), Option B imports only this component for
tree-shake-friendly bundles.
<!-- ─── Option A: global registration (all components) ─── -->
<script type="module">
import '@awc-ui/core/define';
</script>
<!-- ─── Option B: single import (tree-shake only md-skeleton) ─── -->
<script type="module">
import '@awc-ui/core/components/md-skeleton';
</script>
<md-skeleton></md-skeleton>// ─── Option A: typed React wrapper (registers all components) ───
// Importing from '@awc-ui/react' calls defineCustomElements() as a
// side effect, so every md-* element becomes available in the browser.
import { MdSkeleton } from '@awc-ui/react';
export function Example() {
return <MdSkeleton></MdSkeleton>;
}
// ─── Option B: single import (tree-shake to only md-skeleton) ───
// Skip the wrapper and use the raw custom element. Smallest bundle,
// but you lose typed props/events on JSX.
import '@awc-ui/core/components/md-skeleton';
export function ExampleTreeShaken() {
return <md-skeleton></md-skeleton>;
}// ─── Option A: schema module (any md-* element accepted) ───
// Pair with `defineCustomElements(window)` in main.ts.
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@Component({
standalone: true,
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `<md-skeleton></md-skeleton>`,
})
export class ExampleComponent {}
// ─── Option B: typed directive (tree-shake friendly) ───
// Pair with `import '@awc-ui/core/components/md-skeleton'` in main.ts.
import { Component } from '@angular/core';
import { MdSkeleton } from '@awc-ui/angular';
@Component({
standalone: true,
imports: [MdSkeleton],
template: `<md-skeleton></md-skeleton>`,
})
export class ExampleTreeShakenComponent {}<!-- ─── Option A: typed Vue wrapper (registers all components) ─── -->
<script setup lang="ts">
import { MdSkeleton } from '@awc-ui/vue';
</script>
<template>
<MdSkeleton></MdSkeleton>
</template>
<!-- ─── Option B: single import (tree-shake to only md-skeleton) ─── -->
<script setup lang="ts">
import '@awc-ui/core/components/md-skeleton';
</script>
<template>
<md-skeleton></md-skeleton>
</template><!-- ─── Option A: global registration (done once in main entry) ─── -->
<!-- main.ts: -->
<!-- import { defineCustomElements } from '@awc-ui/svelte'; -->
<!-- defineCustomElements(window); -->
<md-skeleton></md-skeleton>
<!-- ─── Option B: single import (tree-shake to only md-skeleton) ─── -->
<script lang="ts">
import '@awc-ui/core/components/md-skeleton';
</script>
<md-skeleton></md-skeleton>| Situation | Use instead |
|---|---|
| Unknown or unstructured content shape | md-loading-indicator |
| A determinate operation with known progress | md-progress-indicator |
| A very short load (under 300ms) | Nothing — a flashing skeleton is worse than the wait |
| A button working after a click | md-button with loading |
| Data that failed to load | An error state — never a permanent skeleton |
| A background task not blocking the view | md-progress-indicator (linear) |
| Variant | Shape | Default box |
|---|---|---|
text | Default. A body-line rectangle; with lines > 1 the last line is tapered to ~60% width | height 1em |
rectangular | Sharp-cornered block for images and media | height 120px |
rounded | Same, with the M3 medium corner radius — cards, thumbnails | height 120px |
circular | 1:1 circle for avatars and icons | 40px |
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: flex; gap: 16px; align-items: center; width: 100%;">
<md-skeleton variant="text" width="180px" announce="false"></md-skeleton>
<md-skeleton variant="rectangular" width="120px" height="72px" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="120px" height="72px" announce="false"></md-skeleton>
<md-skeleton variant="circular" width="48px" height="48px" announce="false"></md-skeleton>
</div>import { MdSkeleton } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'flex', gap: '16px', alignItems: 'center', width: '100%' }}>
<MdSkeleton variant="text" width="180px" announce="false"></MdSkeleton>
<MdSkeleton variant="rectangular" width="120px" height="72px" announce="false"></MdSkeleton>
<MdSkeleton variant="rounded" width="120px" height="72px" announce="false"></MdSkeleton>
<MdSkeleton variant="circular" width="48px" height="48px" announce="false"></MdSkeleton>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display: flex; gap: 16px; align-items: center; width: 100%;">
<md-skeleton variant="text" width="180px" announce="false"></md-skeleton>
<md-skeleton variant="rectangular" width="120px" height="72px" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="120px" height="72px" announce="false"></md-skeleton>
<md-skeleton variant="circular" width="48px" height="48px" announce="false"></md-skeleton>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display: flex; gap: 16px; align-items: center; width: 100%;">
<md-skeleton variant="text" width="180px" announce="false"></md-skeleton>
<md-skeleton variant="rectangular" width="120px" height="72px" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="120px" height="72px" announce="false"></md-skeleton>
<md-skeleton variant="circular" width="48px" height="48px" announce="false"></md-skeleton>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display: flex; gap: 16px; align-items: center; width: 100%;">
<md-skeleton variant="text" width="180px" announce="false"></md-skeleton>
<md-skeleton variant="rectangular" width="120px" height="72px" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="120px" height="72px" announce="false"></md-skeleton>
<md-skeleton variant="circular" width="48px" height="48px" announce="false"></md-skeleton>
</div>lines renders multiple text rows and tapers the last one so it reads as the
end of a paragraph.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<md-skeleton variant="text" lines="4" full-width announce="false"></md-skeleton>import { MdSkeleton } from '@awc-ui/react';
export function Demo() {
return (
<>
<MdSkeleton variant="text" lines="4" fullWidth announce="false"></MdSkeleton>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<md-skeleton variant="text" lines="4" full-width announce="false"></md-skeleton><script setup>
import '@awc-ui/core/define';
</script>
<template>
<md-skeleton variant="text" lines="4" full-width announce="false"></md-skeleton>
</template><script>
import '@awc-ui/core/define';
</script>
<md-skeleton variant="text" lines="4" full-width announce="false"></md-skeleton>width and height take any CSS length. full-width and full-height are the
container-filling shortcuts — full-width wins over a fixed width and over
--md-skeleton-width, which makes it the right tool inside responsive grids.
full-height needs a parent with a definite block size (a flex or grid cell).
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: flex; flex-direction: column; gap: 12px; width: 100%;">
<md-skeleton variant="rounded" full-width height="140px" announce="false"></md-skeleton>
<md-skeleton variant="text" width="60ch" announce="false"></md-skeleton>
<md-skeleton variant="text" width="40%" announce="false"></md-skeleton>
</div>import { MdSkeleton } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px', width: '100%' }}>
<MdSkeleton variant="rounded" fullWidth height="140px" announce="false"></MdSkeleton>
<MdSkeleton variant="text" width="60ch" announce="false"></MdSkeleton>
<MdSkeleton variant="text" width="40%" announce="false"></MdSkeleton>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display: flex; flex-direction: column; gap: 12px; width: 100%;">
<md-skeleton variant="rounded" full-width height="140px" announce="false"></md-skeleton>
<md-skeleton variant="text" width="60ch" announce="false"></md-skeleton>
<md-skeleton variant="text" width="40%" announce="false"></md-skeleton>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px; width: 100%;">
<md-skeleton variant="rounded" full-width height="140px" announce="false"></md-skeleton>
<md-skeleton variant="text" width="60ch" announce="false"></md-skeleton>
<md-skeleton variant="text" width="40%" announce="false"></md-skeleton>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display: flex; flex-direction: column; gap: 12px; width: 100%;">
<md-skeleton variant="rounded" full-width height="140px" announce="false"></md-skeleton>
<md-skeleton variant="text" width="60ch" announce="false"></md-skeleton>
<md-skeleton variant="text" width="40%" announce="false"></md-skeleton>
</div>Both shortcuts track the container live, which is the point — drag the corner of either box below and the shapes reflow rather than staying at their mount size:
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: flex; flex-direction: column; gap: 24px; max-inline-size: 640px;">
<div style="resize: both; overflow: auto; inline-size: 320px; block-size: 200px; min-inline-size: 160px; min-block-size: 96px; padding: 12px; border: 1px dashed var(--md-sys-color-outline); border-radius: 12px;">
<md-skeleton variant="rounded" animation="wave" full-width full-height announce="false"></md-skeleton>
</div>
<div style="resize: both; overflow: auto; inline-size: 480px; block-size: 140px; min-inline-size: 240px; min-block-size: 72px; padding: 12px; border: 1px dashed var(--md-sys-color-outline); border-radius: 12px;">
<div style="display: flex; gap: 12px; block-size: 100%;">
<md-skeleton variant="circular" full-height announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width full-height style="flex: 1;" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-height width="80px" announce="false"></md-skeleton>
</div>
</div>
</div>import { MdSkeleton } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'flex', flexDirection: 'column', gap: '24px', maxInlineSize: '640px' }}>
<div style={{ resize: 'both', overflow: 'auto', inlineSize: '320px', blockSize: '200px', minInlineSize: '160px', minBlockSize: '96px', padding: '12px', border: '1px dashed var(--md-sys-color-outline)', borderRadius: '12px' }}>
<MdSkeleton variant="rounded" animation="wave" fullWidth fullHeight announce="false"></MdSkeleton>
</div>
<div style={{ resize: 'both', overflow: 'auto', inlineSize: '480px', blockSize: '140px', minInlineSize: '240px', minBlockSize: '72px', padding: '12px', border: '1px dashed var(--md-sys-color-outline)', borderRadius: '12px' }}>
<div style={{ display: 'flex', gap: '12px', blockSize: '100%' }}>
<MdSkeleton variant="circular" fullHeight announce="false"></MdSkeleton>
<MdSkeleton variant="rounded" fullWidth fullHeight style={{ flex: '1' }} announce="false"></MdSkeleton>
<MdSkeleton variant="rounded" fullHeight width="80px" announce="false"></MdSkeleton>
</div>
</div>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display: flex; flex-direction: column; gap: 24px; max-inline-size: 640px;">
<div style="resize: both; overflow: auto; inline-size: 320px; block-size: 200px; min-inline-size: 160px; min-block-size: 96px; padding: 12px; border: 1px dashed var(--md-sys-color-outline); border-radius: 12px;">
<md-skeleton variant="rounded" animation="wave" full-width full-height announce="false"></md-skeleton>
</div>
<div style="resize: both; overflow: auto; inline-size: 480px; block-size: 140px; min-inline-size: 240px; min-block-size: 72px; padding: 12px; border: 1px dashed var(--md-sys-color-outline); border-radius: 12px;">
<div style="display: flex; gap: 12px; block-size: 100%;">
<md-skeleton variant="circular" full-height announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width full-height style="flex: 1;" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-height width="80px" announce="false"></md-skeleton>
</div>
</div>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 24px; max-inline-size: 640px;">
<div style="resize: both; overflow: auto; inline-size: 320px; block-size: 200px; min-inline-size: 160px; min-block-size: 96px; padding: 12px; border: 1px dashed var(--md-sys-color-outline); border-radius: 12px;">
<md-skeleton variant="rounded" animation="wave" full-width full-height announce="false"></md-skeleton>
</div>
<div style="resize: both; overflow: auto; inline-size: 480px; block-size: 140px; min-inline-size: 240px; min-block-size: 72px; padding: 12px; border: 1px dashed var(--md-sys-color-outline); border-radius: 12px;">
<div style="display: flex; gap: 12px; block-size: 100%;">
<md-skeleton variant="circular" full-height announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width full-height style="flex: 1;" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-height width="80px" announce="false"></md-skeleton>
</div>
</div>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display: flex; flex-direction: column; gap: 24px; max-inline-size: 640px;">
<div style="resize: both; overflow: auto; inline-size: 320px; block-size: 200px; min-inline-size: 160px; min-block-size: 96px; padding: 12px; border: 1px dashed var(--md-sys-color-outline); border-radius: 12px;">
<md-skeleton variant="rounded" animation="wave" full-width full-height announce="false"></md-skeleton>
</div>
<div style="resize: both; overflow: auto; inline-size: 480px; block-size: 140px; min-inline-size: 240px; min-block-size: 72px; padding: 12px; border: 1px dashed var(--md-sys-color-outline); border-radius: 12px;">
<div style="display: flex; gap: 12px; block-size: 100%;">
<md-skeleton variant="circular" full-height announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width full-height style="flex: 1;" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-height width="80px" announce="false"></md-skeleton>
</div>
</div>
</div>Note the circle in the second box: circular with full-height stays 1:1, so
it grows as a circle rather than stretching into an ellipse.
animation | Effect |
|---|---|
pulse | Default. Gentle opacity fade in and out |
wave | A shimmer gradient sweeping along the inline axis |
none | Static block — the explicit reduced-motion / decorative opt-out |
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: flex; flex-direction: column; gap: 12px; width: 100%;">
<md-skeleton variant="rounded" full-width height="48px" animation="pulse" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width height="48px" animation="wave" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width height="48px" animation="none" announce="false"></md-skeleton>
</div>import { MdSkeleton } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px', width: '100%' }}>
<MdSkeleton variant="rounded" fullWidth height="48px" animation="pulse" announce="false"></MdSkeleton>
<MdSkeleton variant="rounded" fullWidth height="48px" animation="wave" announce="false"></MdSkeleton>
<MdSkeleton variant="rounded" fullWidth height="48px" animation="none" announce="false"></MdSkeleton>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display: flex; flex-direction: column; gap: 12px; width: 100%;">
<md-skeleton variant="rounded" full-width height="48px" animation="pulse" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width height="48px" animation="wave" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width height="48px" animation="none" announce="false"></md-skeleton>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px; width: 100%;">
<md-skeleton variant="rounded" full-width height="48px" animation="pulse" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width height="48px" animation="wave" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width height="48px" animation="none" announce="false"></md-skeleton>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display: flex; flex-direction: column; gap: 12px; width: 100%;">
<md-skeleton variant="rounded" full-width height="48px" animation="pulse" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width height="48px" animation="wave" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width height="48px" animation="none" announce="false"></md-skeleton>
</div>The component already suppresses its animations under
prefers-reduced-motion: reduce — animation-name resolves to none and the
opacity settles at 1, which is exactly what animation="none" renders. There is
nothing to wire up. The
reduced-motion story
stubs the media query and asserts that downgrade.
The preview below reads your setting: if your system asks for reduced motion, the first two shapes are already static and the note under them says so.
Your system allows motion — pulse and wave are animating; only the third is static. Your system requests reduced motion — all three are static, including pulse and wave.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<style>
.rm-state { font: 500 13px/1.4 system-ui, sans-serif; color: var(--md-sys-color-on-surface-variant); }
.rm-state .rm-reduced { display: none; }
@media (prefers-reduced-motion: reduce) {
.rm-state .rm-reduced { display: inline; }
.rm-state .rm-full { display: none; }
}
</style>
<div style="display: flex; flex-direction: column; gap: 12px; inline-size: 100%;">
<md-skeleton variant="rounded" full-width height="40px" animation="pulse" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width height="40px" animation="wave" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width height="40px" animation="none" announce="false"></md-skeleton>
<p class="rm-state">
<span class="rm-full">Your system allows motion — pulse and wave are animating; only the third is static.</span>
<span class="rm-reduced">Your system requests reduced motion — all three are static, including pulse and wave.</span>
</p>
</div>import { MdSkeleton } from '@awc-ui/react';
export function Demo() {
return (
<>
<style>
.rm-state { font: 500 13px/1.4 system-ui, sans-serif; color: var(--md-sys-color-on-surface-variant); }
.rm-state .rm-reduced { display: none; }
@media (prefers-reduced-motion: reduce) {
.rm-state .rm-reduced { display: inline; }
.rm-state .rm-full { display: none; }
}
</style>
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px', inlineSize: '100%' }}>
<MdSkeleton variant="rounded" fullWidth height="40px" animation="pulse" announce="false"></MdSkeleton>
<MdSkeleton variant="rounded" fullWidth height="40px" animation="wave" announce="false"></MdSkeleton>
<MdSkeleton variant="rounded" fullWidth height="40px" animation="none" announce="false"></MdSkeleton>
<p className="rm-state">
<span className="rm-full">Your system allows motion — pulse and wave are animating; only the third is static.</span>
<span className="rm-reduced">Your system requests reduced motion — all three are static, including pulse and wave.</span>
</p>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<style>
.rm-state { font: 500 13px/1.4 system-ui, sans-serif; color: var(--md-sys-color-on-surface-variant); }
.rm-state .rm-reduced { display: none; }
@media (prefers-reduced-motion: reduce) {
.rm-state .rm-reduced { display: inline; }
.rm-state .rm-full { display: none; }
}
</style>
<div style="display: flex; flex-direction: column; gap: 12px; inline-size: 100%;">
<md-skeleton variant="rounded" full-width height="40px" animation="pulse" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width height="40px" animation="wave" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width height="40px" animation="none" announce="false"></md-skeleton>
<p class="rm-state">
<span class="rm-full">Your system allows motion — pulse and wave are animating; only the third is static.</span>
<span class="rm-reduced">Your system requests reduced motion — all three are static, including pulse and wave.</span>
</p>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<style>
.rm-state { font: 500 13px/1.4 system-ui, sans-serif; color: var(--md-sys-color-on-surface-variant); }
.rm-state .rm-reduced { display: none; }
@media (prefers-reduced-motion: reduce) {
.rm-state .rm-reduced { display: inline; }
.rm-state .rm-full { display: none; }
}
</style>
<div style="display: flex; flex-direction: column; gap: 12px; inline-size: 100%;">
<md-skeleton variant="rounded" full-width height="40px" animation="pulse" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width height="40px" animation="wave" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width height="40px" animation="none" announce="false"></md-skeleton>
<p class="rm-state">
<span class="rm-full">Your system allows motion — pulse and wave are animating; only the third is static.</span>
<span class="rm-reduced">Your system requests reduced motion — all three are static, including pulse and wave.</span>
</p>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<style>
.rm-state { font: 500 13px/1.4 system-ui, sans-serif; color: var(--md-sys-color-on-surface-variant); }
.rm-state .rm-reduced { display: none; }
@media (prefers-reduced-motion: reduce) {
.rm-state .rm-reduced { display: inline; }
.rm-state .rm-full { display: none; }
}
</style>
<div style="display: flex; flex-direction: column; gap: 12px; inline-size: 100%;">
<md-skeleton variant="rounded" full-width height="40px" animation="pulse" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width height="40px" animation="wave" announce="false"></md-skeleton>
<md-skeleton variant="rounded" full-width height="40px" animation="none" announce="false"></md-skeleton>
<p class="rm-state">
<span class="rm-full">Your system allows motion — pulse and wave are animating; only the third is static.</span>
<span class="rm-reduced">Your system requests reduced motion — all three are static, including pulse and wave.</span>
</p>
</div>Use animation="none" when you want the static block unconditionally — a
decorative placeholder, or an app that exposes its own motion setting. ## Announcing once
This is the defect to watch for. announce is true by default, so each
skeleton is its own polite live region. In a list of rows, screen-reader users
hear “Loading” once per placeholder.
The fix: one live region for the whole loading area, announce="false" on every
skeleton inside it.
<div role="status" aria-label="Loading contacts">
<div class="row">
<md-skeleton variant="circular" width="40px" height="40px" announce="false"></md-skeleton>
<md-skeleton variant="text" full-width announce="false"></md-skeleton>
</div>
<div class="row">
<md-skeleton variant="circular" width="40px" height="40px" announce="false"></md-skeleton>
<md-skeleton variant="text" full-width announce="false"></md-skeleton>
</div>
</div>import { MdSkeleton } from '@awc-ui/react';
export function ContactsLoading({ rows = 3 }: { rows?: number }) {
return (
<div role="status" aria-label="Loading contacts">
{Array.from({ length: rows }, (_, i) => (
<div className="row" key={i}>
<MdSkeleton variant="circular" width="40px" height="40px" announce={false} />
<MdSkeleton variant="text" fullWidth announce={false} />
</div>
))}
</div>
);
}@Component({
selector: 'app-contacts-loading',
template: `
<div role="status" aria-label="Loading contacts">
<div class="row" *ngFor="let row of rows">
<md-skeleton variant="circular" width="40px" height="40px" announce="false"></md-skeleton>
<md-skeleton variant="text" full-width announce="false"></md-skeleton>
</div>
</div>
`,
})
export class ContactsLoadingComponent {
rows = [0, 1, 2];
}<template>
<div role="status" aria-label="Loading contacts">
<div class="row" v-for="i in 3" :key="i">
<md-skeleton variant="circular" width="40px" height="40px" announce="false" />
<md-skeleton variant="text" full-width announce="false" />
</div>
</div>
</template><div role="status" aria-label="Loading contacts">
{#each Array(3) as _, i}
<div class="row">
<md-skeleton variant="circular" width="40px" height="40px" announce="false" />
<md-skeleton variant="text" full-width announce="false" />
</div>
{/each}
</div><!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div role="status" aria-label="Loading contacts" style="display: grid; gap: 16px; inline-size: 100%; max-inline-size: 420px;">
<div style="display: flex; gap: 12px; align-items: flex-start; padding: 16px; background: var(--md-sys-color-surface-container-low); border-radius: 16px;">
<md-skeleton variant="circular" width="40px" height="40px" announce="false"></md-skeleton>
<div style="flex: 1;">
<md-skeleton width="50%" style="margin-block-end: 8px;" announce="false"></md-skeleton>
<md-skeleton lines="2" announce="false"></md-skeleton>
</div>
</div>
<div style="display: flex; gap: 12px; align-items: flex-start; padding: 16px; background: var(--md-sys-color-surface-container-low); border-radius: 16px;">
<md-skeleton variant="circular" width="40px" height="40px" announce="false"></md-skeleton>
<div style="flex: 1;">
<md-skeleton width="50%" style="margin-block-end: 8px;" announce="false"></md-skeleton>
<md-skeleton lines="2" announce="false"></md-skeleton>
</div>
</div>
</div>import { MdSkeleton } from '@awc-ui/react';
export function Demo() {
return (
<>
<div role="status" aria-label="Loading contacts" style={{ display: 'grid', gap: '16px', inlineSize: '100%', maxInlineSize: '420px' }}>
<div style={{ display: 'flex', gap: '12px', alignItems: 'flex-start', padding: '16px', background: 'var(--md-sys-color-surface-container-low)', borderRadius: '16px' }}>
<MdSkeleton variant="circular" width="40px" height="40px" announce="false"></MdSkeleton>
<div style={{ flex: '1' }}>
<MdSkeleton width="50%" style={{ marginBlockEnd: '8px' }} announce="false"></MdSkeleton>
<MdSkeleton lines="2" announce="false"></MdSkeleton>
</div>
</div>
<div style={{ display: 'flex', gap: '12px', alignItems: 'flex-start', padding: '16px', background: 'var(--md-sys-color-surface-container-low)', borderRadius: '16px' }}>
<MdSkeleton variant="circular" width="40px" height="40px" announce="false"></MdSkeleton>
<div style={{ flex: '1' }}>
<MdSkeleton width="50%" style={{ marginBlockEnd: '8px' }} announce="false"></MdSkeleton>
<MdSkeleton lines="2" announce="false"></MdSkeleton>
</div>
</div>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div role="status" aria-label="Loading contacts" style="display: grid; gap: 16px; inline-size: 100%; max-inline-size: 420px;">
<div style="display: flex; gap: 12px; align-items: flex-start; padding: 16px; background: var(--md-sys-color-surface-container-low); border-radius: 16px;">
<md-skeleton variant="circular" width="40px" height="40px" announce="false"></md-skeleton>
<div style="flex: 1;">
<md-skeleton width="50%" style="margin-block-end: 8px;" announce="false"></md-skeleton>
<md-skeleton lines="2" announce="false"></md-skeleton>
</div>
</div>
<div style="display: flex; gap: 12px; align-items: flex-start; padding: 16px; background: var(--md-sys-color-surface-container-low); border-radius: 16px;">
<md-skeleton variant="circular" width="40px" height="40px" announce="false"></md-skeleton>
<div style="flex: 1;">
<md-skeleton width="50%" style="margin-block-end: 8px;" announce="false"></md-skeleton>
<md-skeleton lines="2" announce="false"></md-skeleton>
</div>
</div>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div role="status" aria-label="Loading contacts" style="display: grid; gap: 16px; inline-size: 100%; max-inline-size: 420px;">
<div style="display: flex; gap: 12px; align-items: flex-start; padding: 16px; background: var(--md-sys-color-surface-container-low); border-radius: 16px;">
<md-skeleton variant="circular" width="40px" height="40px" announce="false"></md-skeleton>
<div style="flex: 1;">
<md-skeleton width="50%" style="margin-block-end: 8px;" announce="false"></md-skeleton>
<md-skeleton lines="2" announce="false"></md-skeleton>
</div>
</div>
<div style="display: flex; gap: 12px; align-items: flex-start; padding: 16px; background: var(--md-sys-color-surface-container-low); border-radius: 16px;">
<md-skeleton variant="circular" width="40px" height="40px" announce="false"></md-skeleton>
<div style="flex: 1;">
<md-skeleton width="50%" style="margin-block-end: 8px;" announce="false"></md-skeleton>
<md-skeleton lines="2" announce="false"></md-skeleton>
</div>
</div>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div role="status" aria-label="Loading contacts" style="display: grid; gap: 16px; inline-size: 100%; max-inline-size: 420px;">
<div style="display: flex; gap: 12px; align-items: flex-start; padding: 16px; background: var(--md-sys-color-surface-container-low); border-radius: 16px;">
<md-skeleton variant="circular" width="40px" height="40px" announce="false"></md-skeleton>
<div style="flex: 1;">
<md-skeleton width="50%" style="margin-block-end: 8px;" announce="false"></md-skeleton>
<md-skeleton lines="2" announce="false"></md-skeleton>
</div>
</div>
<div style="display: flex; gap: 12px; align-items: flex-start; padding: 16px; background: var(--md-sys-color-surface-container-low); border-radius: 16px;">
<md-skeleton variant="circular" width="40px" height="40px" announce="false"></md-skeleton>
<div style="flex: 1;">
<md-skeleton width="50%" style="margin-block-end: 8px;" announce="false"></md-skeleton>
<md-skeleton lines="2" announce="false"></md-skeleton>
</div>
</div>
</div>With announce="false" the skeleton is aria-hidden="true" and drops out of
the accessibility tree entirely — which is exactly right when the region above
it already says “Loading contacts”. The
decorative story
pins that swap in both directions: turning announce off strips role,
aria-busy, aria-live and aria-label and stamps aria-hidden; turning it
back on restores the status role.
There is no timeout and no error state. The skeleton renders until you replace it, so a skeleton that never goes away is a bug in the caller, not in the component. Resolve it on the failure path too.
try { const data = await load(); view.replaceChildren(renderRows(data));} catch { view.replaceChildren(renderError()); // an error state — not a permanent skeleton}The same rule applies to empty results: “no data” is not “loading”. Render a real empty state.
A worked example — one announcement, matched shapes, no layout jump when the real card arrives.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div role="status" aria-label="Loading article" style="inline-size: 100%; max-inline-size: 320px; display: flex; flex-direction: column; gap: 12px;">
<md-skeleton variant="rounded" full-width height="160px" announce="false"></md-skeleton>
<md-skeleton variant="text" width="70%" announce="false"></md-skeleton>
<md-skeleton variant="text" lines="3" full-width announce="false"></md-skeleton>
</div>import { MdSkeleton } from '@awc-ui/react';
export function Demo() {
return (
<>
<div role="status" aria-label="Loading article" style={{ inlineSize: '100%', maxInlineSize: '320px', display: 'flex', flexDirection: 'column', gap: '12px' }}>
<MdSkeleton variant="rounded" fullWidth height="160px" announce="false"></MdSkeleton>
<MdSkeleton variant="text" width="70%" announce="false"></MdSkeleton>
<MdSkeleton variant="text" lines="3" fullWidth announce="false"></MdSkeleton>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div role="status" aria-label="Loading article" style="inline-size: 100%; max-inline-size: 320px; display: flex; flex-direction: column; gap: 12px;">
<md-skeleton variant="rounded" full-width height="160px" announce="false"></md-skeleton>
<md-skeleton variant="text" width="70%" announce="false"></md-skeleton>
<md-skeleton variant="text" lines="3" full-width announce="false"></md-skeleton>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div role="status" aria-label="Loading article" style="inline-size: 100%; max-inline-size: 320px; display: flex; flex-direction: column; gap: 12px;">
<md-skeleton variant="rounded" full-width height="160px" announce="false"></md-skeleton>
<md-skeleton variant="text" width="70%" announce="false"></md-skeleton>
<md-skeleton variant="text" lines="3" full-width announce="false"></md-skeleton>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div role="status" aria-label="Loading article" style="inline-size: 100%; max-inline-size: 320px; display: flex; flex-direction: column; gap: 12px;">
<md-skeleton variant="rounded" full-width height="160px" announce="false"></md-skeleton>
<md-skeleton variant="text" width="70%" announce="false"></md-skeleton>
<md-skeleton variant="text" lines="3" full-width announce="false"></md-skeleton>
</div>| Property | Attribute | Type | Default | Reflects |
|---|---|---|---|---|
variant | variant | 'text' | 'rectangular' | 'rounded' | 'circular' | 'text' | Yes |
animation | animation | 'pulse' | 'wave' | 'none' | 'pulse' | Yes |
lines | lines | number | 1 | Yes |
width | width | string | '' | — |
height | height | string | '' | — |
fullWidth | full-width | boolean | false | Yes |
fullHeight | full-height | boolean | false | Yes |
ariaLabelProp | aria-label | string | 'Loading' | — |
announce | announce | boolean | true | — |
density | density | 0 | -1 | -2 | -3 | -4 | 0 | Yes |
Override on the host element for per-instance theming:
| Property | Description |
|---|---|
--md-skeleton-color | Base placeholder colour |
--md-skeleton-highlight | Wave-shimmer highlight colour |
--md-skeleton-radius | Border-radius for rectangular variant |
--md-skeleton-rounded-radius | Radius for `variant="rounded"` |
--md-skeleton-width | Default inline-size (text/rect) |
--md-skeleton-height | Default block-size (text/rect) |
--md-skeleton-size | Default size for circular variant |
--md-skeleton-line-gap | Gap between text rows (lines > 1) |
--md-skeleton-pulse-duration | Pulse animation duration |
--md-skeleton-wave-duration | Wave animation duration |
--md-skeleton-bloom-duration | Initial mount "bloom" duration |
Style internal elements through shadow DOM with ::part():
| Part | Description |
|---|---|
shape | The rectangular / rounded / circular block. |
The component has no events, methods or slots — one CSS part, shape.
announce (default on) sets role="status", aria-live="polite",
aria-busy="true" and aria-label on the host. Exactly one per loading
region. A chorus of “Loading” announcements is the most common defect here.announce="false" sets aria-hidden="true" — the placeholder becomes purely
visual, which is what you want for every skeleton inside a labelled region.aria-label; the default is the English string "Loading". Prefer a
specific label (“Loading article”) over the generic default.prefers-reduced-motion: reduce;
animation="none" (or overriding the duration custom properties) is the
explicit opt-out.RTL — the shapes are symmetric; the wave animation sweeps along the inline
axis, so it follows direction automatically. See the
RTL story and
RTL.
Density — density="-1…-4" tightens line height and the gap between rows
together: a three-line block goes 64 → 59.6 → 55.2 → 50.8 → 46.4px. Match it
to the density of the content the skeleton stands in for, or the layout will
still jump when the real rows arrive — which is the one thing a skeleton exists
to prevent. See Density.
Text (3 lines)
Rounded
Circular
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<p style="margin: 0 0 8px; font: 500 12px/1.2 system-ui, sans-serif; letter-spacing: .04em; text-transform: uppercase; color: var(--md-sys-color-on-surface-variant);">Text (3 lines)</p>
<div style="display: flex; gap: 20px; align-items: center; flex-wrap: wrap; margin-block-end: 24px;">
<div style="display: flex; gap: 20px; align-items: flex-start; inline-size: 100%; flex-wrap: wrap;">
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="0" full-width announce="false"></md-skeleton></div>
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="-1" full-width announce="false"></md-skeleton></div>
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="-2" full-width announce="false"></md-skeleton></div>
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="-3" full-width announce="false"></md-skeleton></div>
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="-4" full-width announce="false"></md-skeleton></div>
</div>
</div>
<p style="margin: 0 0 8px; font: 500 12px/1.2 system-ui, sans-serif; letter-spacing: .04em; text-transform: uppercase; color: var(--md-sys-color-on-surface-variant);">Rounded</p>
<div style="display: flex; gap: 20px; align-items: center; flex-wrap: wrap; margin-block-end: 24px;">
<md-skeleton variant="rounded" width="88px" height="56px" density="0" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="88px" height="56px" density="-1" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="88px" height="56px" density="-2" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="88px" height="56px" density="-3" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="88px" height="56px" density="-4" announce="false"></md-skeleton>
</div>
<p style="margin: 0 0 8px; font: 500 12px/1.2 system-ui, sans-serif; letter-spacing: .04em; text-transform: uppercase; color: var(--md-sys-color-on-surface-variant);">Circular</p>
<div style="display: flex; gap: 20px; align-items: center; flex-wrap: wrap; margin-block-end: 24px;">
<md-skeleton variant="circular" density="0" announce="false"></md-skeleton>
<md-skeleton variant="circular" density="-1" announce="false"></md-skeleton>
<md-skeleton variant="circular" density="-2" announce="false"></md-skeleton>
<md-skeleton variant="circular" density="-3" announce="false"></md-skeleton>
<md-skeleton variant="circular" density="-4" announce="false"></md-skeleton>
</div>import { MdSkeleton } from '@awc-ui/react';
export function Demo() {
return (
<>
<p style={{ margin: '0 0 8px', font: '500 12px/1.2 system-ui, sans-serif', letterSpacing: '.04em', textTransform: 'uppercase', color: 'var(--md-sys-color-on-surface-variant)' }}>Text (3 lines)</p>
<div style={{ display: 'flex', gap: '20px', alignItems: 'center', flexWrap: 'wrap', marginBlockEnd: '24px' }}>
<div style={{ display: 'flex', gap: '20px', alignItems: 'flex-start', inlineSize: '100%', flexWrap: 'wrap' }}>
<div style={{ flex: '1 1 140px', minInlineSize: '130px' }}><MdSkeleton variant="text" lines="3" density="0" fullWidth announce="false"></MdSkeleton></div>
<div style={{ flex: '1 1 140px', minInlineSize: '130px' }}><MdSkeleton variant="text" lines="3" density="-1" fullWidth announce="false"></MdSkeleton></div>
<div style={{ flex: '1 1 140px', minInlineSize: '130px' }}><MdSkeleton variant="text" lines="3" density="-2" fullWidth announce="false"></MdSkeleton></div>
<div style={{ flex: '1 1 140px', minInlineSize: '130px' }}><MdSkeleton variant="text" lines="3" density="-3" fullWidth announce="false"></MdSkeleton></div>
<div style={{ flex: '1 1 140px', minInlineSize: '130px' }}><MdSkeleton variant="text" lines="3" density="-4" fullWidth announce="false"></MdSkeleton></div>
</div>
</div>
<p style={{ margin: '0 0 8px', font: '500 12px/1.2 system-ui, sans-serif', letterSpacing: '.04em', textTransform: 'uppercase', color: 'var(--md-sys-color-on-surface-variant)' }}>Rounded</p>
<div style={{ display: 'flex', gap: '20px', alignItems: 'center', flexWrap: 'wrap', marginBlockEnd: '24px' }}>
<MdSkeleton variant="rounded" width="88px" height="56px" density="0" announce="false"></MdSkeleton>
<MdSkeleton variant="rounded" width="88px" height="56px" density="-1" announce="false"></MdSkeleton>
<MdSkeleton variant="rounded" width="88px" height="56px" density="-2" announce="false"></MdSkeleton>
<MdSkeleton variant="rounded" width="88px" height="56px" density="-3" announce="false"></MdSkeleton>
<MdSkeleton variant="rounded" width="88px" height="56px" density="-4" announce="false"></MdSkeleton>
</div>
<p style={{ margin: '0 0 8px', font: '500 12px/1.2 system-ui, sans-serif', letterSpacing: '.04em', textTransform: 'uppercase', color: 'var(--md-sys-color-on-surface-variant)' }}>Circular</p>
<div style={{ display: 'flex', gap: '20px', alignItems: 'center', flexWrap: 'wrap', marginBlockEnd: '24px' }}>
<MdSkeleton variant="circular" density="0" announce="false"></MdSkeleton>
<MdSkeleton variant="circular" density="-1" announce="false"></MdSkeleton>
<MdSkeleton variant="circular" density="-2" announce="false"></MdSkeleton>
<MdSkeleton variant="circular" density="-3" announce="false"></MdSkeleton>
<MdSkeleton variant="circular" density="-4" announce="false"></MdSkeleton>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<p style="margin: 0 0 8px; font: 500 12px/1.2 system-ui, sans-serif; letter-spacing: .04em; text-transform: uppercase; color: var(--md-sys-color-on-surface-variant);">Text (3 lines)</p>
<div style="display: flex; gap: 20px; align-items: center; flex-wrap: wrap; margin-block-end: 24px;">
<div style="display: flex; gap: 20px; align-items: flex-start; inline-size: 100%; flex-wrap: wrap;">
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="0" full-width announce="false"></md-skeleton></div>
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="-1" full-width announce="false"></md-skeleton></div>
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="-2" full-width announce="false"></md-skeleton></div>
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="-3" full-width announce="false"></md-skeleton></div>
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="-4" full-width announce="false"></md-skeleton></div>
</div>
</div>
<p style="margin: 0 0 8px; font: 500 12px/1.2 system-ui, sans-serif; letter-spacing: .04em; text-transform: uppercase; color: var(--md-sys-color-on-surface-variant);">Rounded</p>
<div style="display: flex; gap: 20px; align-items: center; flex-wrap: wrap; margin-block-end: 24px;">
<md-skeleton variant="rounded" width="88px" height="56px" density="0" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="88px" height="56px" density="-1" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="88px" height="56px" density="-2" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="88px" height="56px" density="-3" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="88px" height="56px" density="-4" announce="false"></md-skeleton>
</div>
<p style="margin: 0 0 8px; font: 500 12px/1.2 system-ui, sans-serif; letter-spacing: .04em; text-transform: uppercase; color: var(--md-sys-color-on-surface-variant);">Circular</p>
<div style="display: flex; gap: 20px; align-items: center; flex-wrap: wrap; margin-block-end: 24px;">
<md-skeleton variant="circular" density="0" announce="false"></md-skeleton>
<md-skeleton variant="circular" density="-1" announce="false"></md-skeleton>
<md-skeleton variant="circular" density="-2" announce="false"></md-skeleton>
<md-skeleton variant="circular" density="-3" announce="false"></md-skeleton>
<md-skeleton variant="circular" density="-4" announce="false"></md-skeleton>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<p style="margin: 0 0 8px; font: 500 12px/1.2 system-ui, sans-serif; letter-spacing: .04em; text-transform: uppercase; color: var(--md-sys-color-on-surface-variant);">Text (3 lines)</p>
<div style="display: flex; gap: 20px; align-items: center; flex-wrap: wrap; margin-block-end: 24px;">
<div style="display: flex; gap: 20px; align-items: flex-start; inline-size: 100%; flex-wrap: wrap;">
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="0" full-width announce="false"></md-skeleton></div>
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="-1" full-width announce="false"></md-skeleton></div>
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="-2" full-width announce="false"></md-skeleton></div>
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="-3" full-width announce="false"></md-skeleton></div>
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="-4" full-width announce="false"></md-skeleton></div>
</div>
</div>
<p style="margin: 0 0 8px; font: 500 12px/1.2 system-ui, sans-serif; letter-spacing: .04em; text-transform: uppercase; color: var(--md-sys-color-on-surface-variant);">Rounded</p>
<div style="display: flex; gap: 20px; align-items: center; flex-wrap: wrap; margin-block-end: 24px;">
<md-skeleton variant="rounded" width="88px" height="56px" density="0" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="88px" height="56px" density="-1" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="88px" height="56px" density="-2" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="88px" height="56px" density="-3" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="88px" height="56px" density="-4" announce="false"></md-skeleton>
</div>
<p style="margin: 0 0 8px; font: 500 12px/1.2 system-ui, sans-serif; letter-spacing: .04em; text-transform: uppercase; color: var(--md-sys-color-on-surface-variant);">Circular</p>
<div style="display: flex; gap: 20px; align-items: center; flex-wrap: wrap; margin-block-end: 24px;">
<md-skeleton variant="circular" density="0" announce="false"></md-skeleton>
<md-skeleton variant="circular" density="-1" announce="false"></md-skeleton>
<md-skeleton variant="circular" density="-2" announce="false"></md-skeleton>
<md-skeleton variant="circular" density="-3" announce="false"></md-skeleton>
<md-skeleton variant="circular" density="-4" announce="false"></md-skeleton>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<p style="margin: 0 0 8px; font: 500 12px/1.2 system-ui, sans-serif; letter-spacing: .04em; text-transform: uppercase; color: var(--md-sys-color-on-surface-variant);">Text (3 lines)</p>
<div style="display: flex; gap: 20px; align-items: center; flex-wrap: wrap; margin-block-end: 24px;">
<div style="display: flex; gap: 20px; align-items: flex-start; inline-size: 100%; flex-wrap: wrap;">
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="0" full-width announce="false"></md-skeleton></div>
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="-1" full-width announce="false"></md-skeleton></div>
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="-2" full-width announce="false"></md-skeleton></div>
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="-3" full-width announce="false"></md-skeleton></div>
<div style="flex: 1 1 140px; min-inline-size: 130px;"><md-skeleton variant="text" lines="3" density="-4" full-width announce="false"></md-skeleton></div>
</div>
</div>
<p style="margin: 0 0 8px; font: 500 12px/1.2 system-ui, sans-serif; letter-spacing: .04em; text-transform: uppercase; color: var(--md-sys-color-on-surface-variant);">Rounded</p>
<div style="display: flex; gap: 20px; align-items: center; flex-wrap: wrap; margin-block-end: 24px;">
<md-skeleton variant="rounded" width="88px" height="56px" density="0" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="88px" height="56px" density="-1" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="88px" height="56px" density="-2" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="88px" height="56px" density="-3" announce="false"></md-skeleton>
<md-skeleton variant="rounded" width="88px" height="56px" density="-4" announce="false"></md-skeleton>
</div>
<p style="margin: 0 0 8px; font: 500 12px/1.2 system-ui, sans-serif; letter-spacing: .04em; text-transform: uppercase; color: var(--md-sys-color-on-surface-variant);">Circular</p>
<div style="display: flex; gap: 20px; align-items: center; flex-wrap: wrap; margin-block-end: 24px;">
<md-skeleton variant="circular" density="0" announce="false"></md-skeleton>
<md-skeleton variant="circular" density="-1" announce="false"></md-skeleton>
<md-skeleton variant="circular" density="-2" announce="false"></md-skeleton>
<md-skeleton variant="circular" density="-3" announce="false"></md-skeleton>
<md-skeleton variant="circular" density="-4" announce="false"></md-skeleton>
</div>i18n — the only text is aria-label; translate it, and translate the label
on the wrapping live region too.
| Custom property | Purpose |
|---|---|
--md-skeleton-color | Base placeholder fill |
--md-skeleton-highlight | Wave shimmer highlight |
--md-skeleton-radius | Radius for rectangular |
--md-skeleton-rounded-radius | Radius for rounded |
--md-skeleton-width / --md-skeleton-height | Default box for text and rectangles |
--md-skeleton-size | Default size for circular |
--md-skeleton-line-gap | Gap between text rows when lines > 1 |
--md-skeleton-pulse-duration / --md-skeleton-wave-duration | Animation timing |
--md-skeleton-bloom-duration | Initial mount bloom |
CSS part — shape.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<md-skeleton
variant="rounded"
full-width
height="64px"
animation="wave"
announce="false"
style="--md-skeleton-color: var(--md-sys-color-secondary-container); --md-skeleton-wave-duration: 2.4s;"
></md-skeleton>import { MdSkeleton } from '@awc-ui/react';
export function Demo() {
return (
<>
<MdSkeleton
variant="rounded"
fullWidth
height="64px"
animation="wave"
announce="false"
style={{ '--md-skeleton-color': 'var(--md-sys-color-secondary-container)', '--md-skeleton-wave-duration': '2.4s' }}
></MdSkeleton>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<md-skeleton
variant="rounded"
full-width
height="64px"
animation="wave"
announce="false"
style="--md-skeleton-color: var(--md-sys-color-secondary-container); --md-skeleton-wave-duration: 2.4s;"
></md-skeleton><script setup>
import '@awc-ui/core/define';
</script>
<template>
<md-skeleton
variant="rounded"
full-width
height="64px"
animation="wave"
announce="false"
style="--md-skeleton-color: var(--md-sys-color-secondary-container); --md-skeleton-wave-duration: 2.4s;"
></md-skeleton>
</template><script>
import '@awc-ui/core/define';
</script>
<md-skeleton
variant="rounded"
full-width
height="64px"
animation="wave"
announce="false"
style="--md-skeleton-color: var(--md-sys-color-secondary-container); --md-skeleton-wave-duration: 2.4s;"
></md-skeleton>The placeholder colour is the one to get right: it has to read as absent content against the surface behind it. Check it in both themes — the dark-theme story is the counterpart to this one.
md-loading-indicator ·
md-progress-indicator ·
md-card ·
md-list ·
md-avatar
md-skeletonTwo artefacts to give your AI agent so it generates correct UI with this component. The per-component spec answers "how do I use this exact tag?". The main-llm spec answers "which tag should I pick in the first place?".
md-skeleton spec card
Identity · when to use / when NOT · decision cues · behavioural contract · do/don't · anti-patterns · full API. Paste into your agent when you're implementing with this component.
System-prompt preamble · decision matrix · token reference · page recipes · anti-patterns. Paste into the system prompt at the start of a piece of work.