md-loading-indicator 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.
The M3 Expressive loading moment. A morphing-shape indicator for
indeterminate waits — distinct from a progress indicator, which reports how far
along something is. Two variants, a five-rung density ladder, a themable
shape part, and a three-prop API on purpose.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<md-loading-indicator label="Loading"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Loading results"></md-loading-indicator>import { MdLoadingIndicator } from '@awc-ui/react';
export function Demo() {
return (
<>
<MdLoadingIndicator label="Loading"></MdLoadingIndicator>
<MdLoadingIndicator variant="contained" label="Loading results"></MdLoadingIndicator>
</>
);
}// 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-loading-indicator label="Loading"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Loading results"></md-loading-indicator><script setup>
import '@awc-ui/core/define';
</script>
<template>
<md-loading-indicator label="Loading"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Loading results"></md-loading-indicator>
</template><script>
import '@awc-ui/core/define';
</script>
<md-loading-indicator label="Loading"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Loading results"></md-loading-indicator>
Already installed? See the
Installation guide for one-time package setup
(core + tokens, fonts). Each tab below shows two patterns for using
md-loading-indicator 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-loading-indicator) ─── -->
<script type="module">
import '@awc-ui/core/components/md-loading-indicator';
</script>
<md-loading-indicator></md-loading-indicator>// ─── 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 { MdLoadingIndicator } from '@awc-ui/react';
export function Example() {
return <MdLoadingIndicator></MdLoadingIndicator>;
}
// ─── Option B: single import (tree-shake to only md-loading-indicator) ───
// 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-loading-indicator';
export function ExampleTreeShaken() {
return <md-loading-indicator></md-loading-indicator>;
}// ─── 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-loading-indicator></md-loading-indicator>`,
})
export class ExampleComponent {}
// ─── Option B: typed directive (tree-shake friendly) ───
// Pair with `import '@awc-ui/core/components/md-loading-indicator'` in main.ts.
import { Component } from '@angular/core';
import { MdLoadingIndicator } from '@awc-ui/angular';
@Component({
standalone: true,
imports: [MdLoadingIndicator],
template: `<md-loading-indicator></md-loading-indicator>`,
})
export class ExampleTreeShakenComponent {}<!-- ─── Option A: typed Vue wrapper (registers all components) ─── -->
<script setup lang="ts">
import { MdLoadingIndicator } from '@awc-ui/vue';
</script>
<template>
<MdLoadingIndicator></MdLoadingIndicator>
</template>
<!-- ─── Option B: single import (tree-shake to only md-loading-indicator) ─── -->
<script setup lang="ts">
import '@awc-ui/core/components/md-loading-indicator';
</script>
<template>
<md-loading-indicator></md-loading-indicator>
</template><!-- ─── Option A: global registration (done once in main entry) ─── -->
<!-- main.ts: -->
<!-- import { defineCustomElements } from '@awc-ui/svelte'; -->
<!-- defineCustomElements(window); -->
<md-loading-indicator></md-loading-indicator>
<!-- ─── Option B: single import (tree-shake to only md-loading-indicator) ─── -->
<script lang="ts">
import '@awc-ui/core/components/md-loading-indicator';
</script>
<md-loading-indicator></md-loading-indicator>md-select,
md-multi-select,
md-autocomplete and
md-search use it internally.| Situation | Use instead |
|---|---|
| You know how far along the operation is | md-progress-indicator (determinate) |
| Content whose shape is known | md-skeleton |
| A button working after a click | md-button with loading |
| An operation that will become determinate | md-progress-indicator — M3 says don’t transition from a loading indicator |
| A long background job not blocking the view | Linear md-progress-indicator |
variant is the only visual switch. uncontained (the default) paints the bare
morphing shape onto whatever surface it sits on; contained adds its own
container behind it and re-tones the shape to on-primary-container so it reads
against that backdrop.
| Variant | Use for |
|---|---|
uncontained | Default. On an existing surface — a list, a card body, a picker |
contained | Over content or imagery, where the shape needs its own backdrop |
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<md-loading-indicator label="Uncontained"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Contained"></md-loading-indicator>import { MdLoadingIndicator } from '@awc-ui/react';
export function Demo() {
return (
<>
<MdLoadingIndicator label="Uncontained"></MdLoadingIndicator>
<MdLoadingIndicator variant="contained" label="Contained"></MdLoadingIndicator>
</>
);
}// 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-loading-indicator label="Uncontained"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Contained"></md-loading-indicator><script setup>
import '@awc-ui/core/define';
</script>
<template>
<md-loading-indicator label="Uncontained"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Contained"></md-loading-indicator>
</template><script>
import '@awc-ui/core/define';
</script>
<md-loading-indicator label="Uncontained"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Contained"></md-loading-indicator>There is no size prop — scale it with the two custom properties. The defaults
are a 48px box around a 38px shape, so set
--md-loading-indicator-shape-size alongside --md-loading-indicator-size to
keep that proportion.
| Custom property | Default | Scales |
|---|---|---|
--md-loading-indicator-size | 48px | The overall box — and the contained backdrop |
--md-loading-indicator-shape-size | 38px | The morphing shape inside it |
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<md-loading-indicator label="Small" style="--md-loading-indicator-size: 32px; --md-loading-indicator-shape-size: 24px;"></md-loading-indicator>
<md-loading-indicator label="Default"></md-loading-indicator>
<md-loading-indicator label="Large" style="--md-loading-indicator-size: 64px; --md-loading-indicator-shape-size: 52px;"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Small contained" style="--md-loading-indicator-size: 32px; --md-loading-indicator-shape-size: 24px;"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Default contained"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Large contained" style="--md-loading-indicator-size: 64px; --md-loading-indicator-shape-size: 52px;"></md-loading-indicator>import { MdLoadingIndicator } from '@awc-ui/react';
export function Demo() {
return (
<>
<MdLoadingIndicator label="Small" style={{ '--md-loading-indicator-size': '32px', '--md-loading-indicator-shape-size': '24px' }}></MdLoadingIndicator>
<MdLoadingIndicator label="Default"></MdLoadingIndicator>
<MdLoadingIndicator label="Large" style={{ '--md-loading-indicator-size': '64px', '--md-loading-indicator-shape-size': '52px' }}></MdLoadingIndicator>
<MdLoadingIndicator variant="contained" label="Small contained" style={{ '--md-loading-indicator-size': '32px', '--md-loading-indicator-shape-size': '24px' }}></MdLoadingIndicator>
<MdLoadingIndicator variant="contained" label="Default contained"></MdLoadingIndicator>
<MdLoadingIndicator variant="contained" label="Large contained" style={{ '--md-loading-indicator-size': '64px', '--md-loading-indicator-shape-size': '52px' }}></MdLoadingIndicator>
</>
);
}// 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-loading-indicator label="Small" style="--md-loading-indicator-size: 32px; --md-loading-indicator-shape-size: 24px;"></md-loading-indicator>
<md-loading-indicator label="Default"></md-loading-indicator>
<md-loading-indicator label="Large" style="--md-loading-indicator-size: 64px; --md-loading-indicator-shape-size: 52px;"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Small contained" style="--md-loading-indicator-size: 32px; --md-loading-indicator-shape-size: 24px;"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Default contained"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Large contained" style="--md-loading-indicator-size: 64px; --md-loading-indicator-shape-size: 52px;"></md-loading-indicator><script setup>
import '@awc-ui/core/define';
</script>
<template>
<md-loading-indicator label="Small" style="--md-loading-indicator-size: 32px; --md-loading-indicator-shape-size: 24px;"></md-loading-indicator>
<md-loading-indicator label="Default"></md-loading-indicator>
<md-loading-indicator label="Large" style="--md-loading-indicator-size: 64px; --md-loading-indicator-shape-size: 52px;"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Small contained" style="--md-loading-indicator-size: 32px; --md-loading-indicator-shape-size: 24px;"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Default contained"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Large contained" style="--md-loading-indicator-size: 64px; --md-loading-indicator-shape-size: 52px;"></md-loading-indicator>
</template><script>
import '@awc-ui/core/define';
</script>
<md-loading-indicator label="Small" style="--md-loading-indicator-size: 32px; --md-loading-indicator-shape-size: 24px;"></md-loading-indicator>
<md-loading-indicator label="Default"></md-loading-indicator>
<md-loading-indicator label="Large" style="--md-loading-indicator-size: 64px; --md-loading-indicator-shape-size: 52px;"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Small contained" style="--md-loading-indicator-size: 32px; --md-loading-indicator-shape-size: 24px;"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Default contained"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Large contained" style="--md-loading-indicator-size: 64px; --md-loading-indicator-shape-size: 52px;"></md-loading-indicator>M3’s rule is that the indicator must stay in view for the whole activity. An indicator that scrolls off-screen hides the status and implies the refresh belongs to one component rather than the screen — pin it.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="inline-size: 100%; max-inline-size: 420px; display: flex; flex-direction: column; gap: 16px;">
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; min-block-size: 160px; padding: 16px; border-radius: 12px; background: var(--md-sys-color-surface-container-low); color: var(--md-sys-color-on-surface);">
<md-loading-indicator variant="contained" label="Loading content"></md-loading-indicator>
<span style="font-size: 14px; color: var(--md-sys-color-on-surface-variant);">Loading content…</span>
</div>
<div style="display: flex; align-items: center; gap: 12px; padding: 16px; border-radius: 12px; background: var(--md-sys-color-surface-container-low); color: var(--md-sys-color-on-surface);">
<md-loading-indicator label="Fetching results" style="--md-loading-indicator-size: 32px; --md-loading-indicator-shape-size: 24px;"></md-loading-indicator>
<span style="font-size: 14px;">Fetching results…</span>
</div>
</div>import { MdLoadingIndicator } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ inlineSize: '100%', maxInlineSize: '420px', display: 'flex', flexDirection: 'column', gap: '16px' }}>
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: '12px', minBlockSize: '160px', padding: '16px', borderRadius: '12px', background: 'var(--md-sys-color-surface-container-low)', color: 'var(--md-sys-color-on-surface)' }}>
<MdLoadingIndicator variant="contained" label="Loading content"></MdLoadingIndicator>
<span style={{ fontSize: '14px', color: 'var(--md-sys-color-on-surface-variant)' }}>Loading content…</span>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: '12px', padding: '16px', borderRadius: '12px', background: 'var(--md-sys-color-surface-container-low)', color: 'var(--md-sys-color-on-surface)' }}>
<MdLoadingIndicator label="Fetching results" style={{ '--md-loading-indicator-size': '32px', '--md-loading-indicator-shape-size': '24px' }}></MdLoadingIndicator>
<span style={{ fontSize: '14px' }}>Fetching results…</span>
</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="inline-size: 100%; max-inline-size: 420px; display: flex; flex-direction: column; gap: 16px;">
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; min-block-size: 160px; padding: 16px; border-radius: 12px; background: var(--md-sys-color-surface-container-low); color: var(--md-sys-color-on-surface);">
<md-loading-indicator variant="contained" label="Loading content"></md-loading-indicator>
<span style="font-size: 14px; color: var(--md-sys-color-on-surface-variant);">Loading content…</span>
</div>
<div style="display: flex; align-items: center; gap: 12px; padding: 16px; border-radius: 12px; background: var(--md-sys-color-surface-container-low); color: var(--md-sys-color-on-surface);">
<md-loading-indicator label="Fetching results" style="--md-loading-indicator-size: 32px; --md-loading-indicator-shape-size: 24px;"></md-loading-indicator>
<span style="font-size: 14px;">Fetching results…</span>
</div>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="inline-size: 100%; max-inline-size: 420px; display: flex; flex-direction: column; gap: 16px;">
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; min-block-size: 160px; padding: 16px; border-radius: 12px; background: var(--md-sys-color-surface-container-low); color: var(--md-sys-color-on-surface);">
<md-loading-indicator variant="contained" label="Loading content"></md-loading-indicator>
<span style="font-size: 14px; color: var(--md-sys-color-on-surface-variant);">Loading content…</span>
</div>
<div style="display: flex; align-items: center; gap: 12px; padding: 16px; border-radius: 12px; background: var(--md-sys-color-surface-container-low); color: var(--md-sys-color-on-surface);">
<md-loading-indicator label="Fetching results" style="--md-loading-indicator-size: 32px; --md-loading-indicator-shape-size: 24px;"></md-loading-indicator>
<span style="font-size: 14px;">Fetching results…</span>
</div>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="inline-size: 100%; max-inline-size: 420px; display: flex; flex-direction: column; gap: 16px;">
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; min-block-size: 160px; padding: 16px; border-radius: 12px; background: var(--md-sys-color-surface-container-low); color: var(--md-sys-color-on-surface);">
<md-loading-indicator variant="contained" label="Loading content"></md-loading-indicator>
<span style="font-size: 14px; color: var(--md-sys-color-on-surface-variant);">Loading content…</span>
</div>
<div style="display: flex; align-items: center; gap: 12px; padding: 16px; border-radius: 12px; background: var(--md-sys-color-surface-container-low); color: var(--md-sys-color-on-surface);">
<md-loading-indicator label="Fetching results" style="--md-loading-indicator-size: 32px; --md-loading-indicator-shape-size: 24px;"></md-loading-indicator>
<span style="font-size: 14px;">Fetching results…</span>
</div>
</div>It has no timeout — it spins until you remove it. Always resolve it on failure as well as on success. Press either button: the failing one removes the indicator just as the succeeding one does, and shows an error in its place.
<div style="display: flex; gap: 12px;">
<md-button variant="filled" id="load-ok">Load (succeeds)</md-button>
<md-button variant="outlined" id="load-fail">Load (fails)</md-button>
</div>
<div id="results">Press a button to start.</div>
<script type="module">
const results = document.getElementById('results');
async function load(shouldFail) {
results.innerHTML =
'<md-loading-indicator variant="contained" label="Loading results"></md-loading-indicator>';
try {
results.textContent = await fetchResults(shouldFail);
} catch {
results.textContent = 'Could not load results.'; // the indicator goes either way
}
}
document.getElementById('load-ok').addEventListener('mdClick', () => load(false));
document.getElementById('load-fail').addEventListener('mdClick', () => load(true));
</script>import { MdButton, MdLoadingIndicator } from '@awc-ui/react';
import { useState } from 'react';
export function Results() {
const [loading, setLoading] = useState(false);
const [text, setText] = useState('Press a button to start.');
async function load(shouldFail: boolean) {
setLoading(true);
try {
setText(await fetchResults(shouldFail));
} catch {
setText('Could not load results.');
} finally {
setLoading(false); // success or failure
}
}
return (
<>
<MdButton variant="filled" onMdClick={() => load(false)}>Load (succeeds)</MdButton>
<MdButton variant="outlined" onMdClick={() => load(true)}>Load (fails)</MdButton>
{loading
? <MdLoadingIndicator variant="contained" label="Loading results" />
: <p>{text}</p>}
</>
);
}import { Component } from '@angular/core';
@Component({
selector: 'app-results',
template: `
<md-button variant="filled" (mdClick)="load(false)">Load (succeeds)</md-button>
<md-button variant="outlined" (mdClick)="load(true)">Load (fails)</md-button>
<md-loading-indicator *ngIf="loading" variant="contained" label="Loading results"></md-loading-indicator>
<p *ngIf="!loading">{{ text }}</p>
`,
})
export class ResultsComponent {
loading = false;
text = 'Press a button to start.';
async load(shouldFail: boolean) {
this.loading = true;
try {
this.text = await fetchResults(shouldFail);
} catch {
this.text = 'Could not load results.';
} finally {
this.loading = false; // success or failure
}
}
}<script setup lang="ts">
import { ref } from 'vue';
const loading = ref(false);
const text = ref('Press a button to start.');
async function load(shouldFail: boolean) {
loading.value = true;
try {
text.value = await fetchResults(shouldFail);
} catch {
text.value = 'Could not load results.';
} finally {
loading.value = false; // success or failure
}
}
</script>
<template>
<md-button variant="filled" @mdClick="load(false)">Load (succeeds)</md-button>
<md-button variant="outlined" @mdClick="load(true)">Load (fails)</md-button>
<md-loading-indicator v-if="loading" variant="contained" label="Loading results" />
<p v-else>{{ text }}</p>
</template><script lang="ts">
let loading = false;
let text = 'Press a button to start.';
async function load(shouldFail: boolean) {
loading = true;
try {
text = await fetchResults(shouldFail);
} catch {
text = 'Could not load results.';
} finally {
loading = false; // success or failure
}
}
</script>
<md-button variant="filled" on:mdClick={() => load(false)}>Load (succeeds)</md-button>
<md-button variant="outlined" on:mdClick={() => load(true)}>Load (fails)</md-button>
{#if loading}
<md-loading-indicator variant="contained" label="Loading results" />
{:else}
<p>{text}</p>
{/if}The same promise for a fetch that starts on mount — note the finally /
catch arm in every one:
<div id="results-slot">
<md-loading-indicator label="Loading results"></md-loading-indicator>
</div>
<script type="module">
const slot = document.getElementById('results-slot');
try {
renderResults(await fetchData());
} catch {
renderError();
} finally {
slot.querySelector('md-loading-indicator')?.remove(); // success or failure
}
</script>import { MdLoadingIndicator } from '@awc-ui/react';
import { useEffect, useState } from 'react';
export function Results() {
const [state, setState] = useState<'loading' | 'ready' | 'error'>('loading');
const [rows, setRows] = useState<Row[]>([]);
useEffect(() => {
fetchData()
.then((r) => { setRows(r); setState('ready'); })
.catch(() => setState('error')); // never leave it spinning
}, []);
if (state === 'loading') return <MdLoadingIndicator label="Loading results" />;
if (state === 'error') return <ErrorState />;
return <RowList rows={rows} />;
}import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-results',
template: `
<md-loading-indicator *ngIf="state === 'loading'" label="Loading results"></md-loading-indicator>
<app-error-state *ngIf="state === 'error'"></app-error-state>
<app-row-list *ngIf="state === 'ready'" [rows]="rows"></app-row-list>
`,
})
export class ResultsComponent implements OnInit {
state: 'loading' | 'ready' | 'error' = 'loading';
rows: Row[] = [];
async ngOnInit() {
try {
this.rows = await fetchData();
this.state = 'ready';
} catch {
this.state = 'error'; // never leave it spinning
}
}
}<script setup lang="ts">
import { ref, onMounted } from 'vue';
const state = ref<'loading' | 'ready' | 'error'>('loading');
const rows = ref<Row[]>([]);
onMounted(async () => {
try {
rows.value = await fetchData();
state.value = 'ready';
} catch {
state.value = 'error'; // never leave it spinning
}
});
</script>
<template>
<md-loading-indicator v-if="state === 'loading'" label="Loading results" />
<ErrorState v-else-if="state === 'error'" />
<RowList v-else :rows="rows" />
</template><script lang="ts">
import { onMount } from 'svelte';
let state: 'loading' | 'ready' | 'error' = 'loading';
let rows: Row[] = [];
onMount(async () => {
try {
rows = await fetchData();
state = 'ready';
} catch {
state = 'error'; // never leave it spinning
}
});
</script>
{#if state === 'loading'}
<md-loading-indicator label="Loading results" />
{:else if state === 'error'}
<ErrorState />
{:else}
<RowList {rows} />
{/if}| Property | Attribute | Type | Default | Reflects |
|---|---|---|---|---|
variant | variant | 'uncontained' | 'contained' | 'uncontained' | Yes |
label | label | string | 'Loading' | — |
density | density | 0 | -1 | -2 | -3 | -4 | 0 | Yes |
Override on the host element for per-instance theming:
| Property | Description |
|---|---|
--md-loading-indicator-color | Indicator shape color |
--md-loading-indicator-size | Overall component size (default 48px) |
--md-loading-indicator-shape-size | Morphing shape size (default 38px) |
--md-loading-indicator-container-color | Container background (contained variant) |
--md-loading-indicator-container-shape | Container border radius |
Style internal elements through shadow DOM with ::part():
| Part | Description |
|---|---|
shape | The morphing indicator shape |
role="progressbar" with aria-live="polite", plus an
internal role="status" element holding the same text — so the label is
announced when the indicator appears.label is the accessible name and defaults to the English "Loading". Make it
specific — “Refreshing messages”.secondary at 2px offset, following the
container shape.prefers-reduced-motion is already handled — the morph is replaced by a
gentle opacity pulse on a circle. You do not need to write that CSS.Tab into the first one below to see the focus ring; the last pair shows the announce-the-result pattern — a live region you own, next to the indicator you remove.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: grid; grid-template-columns: auto 1fr; gap: 14px 16px; align-items: center;">
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">focus</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;">
<md-loading-indicator tabindex="0" label="Refreshing messages"></md-loading-indicator>
<md-loading-indicator variant="contained" tabindex="0" label="Refreshing messages"></md-loading-indicator>
</div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">label</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;">
<md-loading-indicator label="Loading"></md-loading-indicator>
<md-loading-indicator label="Refreshing messages"></md-loading-indicator>
</div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">result</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;">
<md-loading-indicator label="Searching invoices"></md-loading-indicator>
<output role="status" style="font: 400 14px/1.4 system-ui, sans-serif; color: var(--md-sys-color-on-surface-variant);">Your app announces "12 invoices found" here — the component cannot.</output>
</div>
</div>import { MdLoadingIndicator } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'grid', gridTemplateColumns: 'auto 1fr', gap: '14px 16px', alignItems: 'center' }}>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace, monospace' }}>focus</span>
<div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center' }}>
<MdLoadingIndicator tabIndex="0" label="Refreshing messages"></MdLoadingIndicator>
<MdLoadingIndicator variant="contained" tabIndex="0" label="Refreshing messages"></MdLoadingIndicator>
</div>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace, monospace' }}>label</span>
<div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center' }}>
<MdLoadingIndicator label="Loading"></MdLoadingIndicator>
<MdLoadingIndicator label="Refreshing messages"></MdLoadingIndicator>
</div>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace, monospace' }}>result</span>
<div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center' }}>
<MdLoadingIndicator label="Searching invoices"></MdLoadingIndicator>
<output role="status" style={{ font: '400 14px/1.4 system-ui, sans-serif', color: 'var(--md-sys-color-on-surface-variant)' }}>Your app announces "12 invoices found" here — the component cannot.</output>
</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: grid; grid-template-columns: auto 1fr; gap: 14px 16px; align-items: center;">
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">focus</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;">
<md-loading-indicator tabindex="0" label="Refreshing messages"></md-loading-indicator>
<md-loading-indicator variant="contained" tabindex="0" label="Refreshing messages"></md-loading-indicator>
</div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">label</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;">
<md-loading-indicator label="Loading"></md-loading-indicator>
<md-loading-indicator label="Refreshing messages"></md-loading-indicator>
</div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">result</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;">
<md-loading-indicator label="Searching invoices"></md-loading-indicator>
<output role="status" style="font: 400 14px/1.4 system-ui, sans-serif; color: var(--md-sys-color-on-surface-variant);">Your app announces "12 invoices found" here — the component cannot.</output>
</div>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display: grid; grid-template-columns: auto 1fr; gap: 14px 16px; align-items: center;">
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">focus</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;">
<md-loading-indicator tabindex="0" label="Refreshing messages"></md-loading-indicator>
<md-loading-indicator variant="contained" tabindex="0" label="Refreshing messages"></md-loading-indicator>
</div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">label</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;">
<md-loading-indicator label="Loading"></md-loading-indicator>
<md-loading-indicator label="Refreshing messages"></md-loading-indicator>
</div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">result</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;">
<md-loading-indicator label="Searching invoices"></md-loading-indicator>
<output role="status" style="font: 400 14px/1.4 system-ui, sans-serif; color: var(--md-sys-color-on-surface-variant);">Your app announces "12 invoices found" here — the component cannot.</output>
</div>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display: grid; grid-template-columns: auto 1fr; gap: 14px 16px; align-items: center;">
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">focus</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;">
<md-loading-indicator tabindex="0" label="Refreshing messages"></md-loading-indicator>
<md-loading-indicator variant="contained" tabindex="0" label="Refreshing messages"></md-loading-indicator>
</div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">label</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;">
<md-loading-indicator label="Loading"></md-loading-indicator>
<md-loading-indicator label="Refreshing messages"></md-loading-indicator>
</div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">result</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;">
<md-loading-indicator label="Searching invoices"></md-loading-indicator>
<output role="status" style="font: 400 14px/1.4 system-ui, sans-serif; color: var(--md-sys-color-on-surface-variant);">Your app announces "12 invoices found" here — the component cannot.</output>
</div>
</div>The middle row is the one to copy from: "Loading" is a default, not a
decision. Anything that names the work — “Refreshing messages”, “Searching
invoices” — tells a screen-reader user what is actually taking time.
RTL — the morph is radially symmetric and the component is a single
centred box, so there is nothing to flip. dir still matters for the text you
put next to it, which is where the mirroring actually happens. See
RTL.
<div dir="rtl"> <md-loading-indicator variant="contained" label="جارٍ التحميل"></md-loading-indicator></div>The two rows below share one markup structure — same elements, same order, same
styles; only dir and the translated strings differ. Nothing about the
indicator is re-authored, and the text beside it moves to the other edge on its
own:
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: grid; grid-template-columns: auto 1fr; gap: 14px 16px; align-items: center;">
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">ltr</span>
<div dir="ltr" style="display: flex; gap: 12px; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="Loading results"></md-loading-indicator>
<span>Loading results…</span>
<md-loading-indicator variant="contained" label="Refreshing"></md-loading-indicator>
</div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">rtl</span>
<div dir="rtl" style="display: flex; gap: 12px; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="جارٍ تحميل النتائج"></md-loading-indicator>
<span>…جارٍ تحميل النتائج</span>
<md-loading-indicator variant="contained" label="جارٍ التحديث"></md-loading-indicator>
</div>
</div>import { MdLoadingIndicator } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'grid', gridTemplateColumns: 'auto 1fr', gap: '14px 16px', alignItems: 'center' }}>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace, monospace' }}>ltr</span>
<div dir="ltr" style={{ display: 'flex', gap: '12px', flexWrap: 'wrap', alignItems: 'center', font: '400 14px/1.4 system-ui, sans-serif' }}>
<MdLoadingIndicator label="Loading results"></MdLoadingIndicator>
<span>Loading results…</span>
<MdLoadingIndicator variant="contained" label="Refreshing"></MdLoadingIndicator>
</div>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace, monospace' }}>rtl</span>
<div dir="rtl" style={{ display: 'flex', gap: '12px', flexWrap: 'wrap', alignItems: 'center', font: '400 14px/1.4 system-ui, sans-serif' }}>
<MdLoadingIndicator label="جارٍ تحميل النتائج"></MdLoadingIndicator>
<span>…جارٍ تحميل النتائج</span>
<MdLoadingIndicator variant="contained" label="جارٍ التحديث"></MdLoadingIndicator>
</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: grid; grid-template-columns: auto 1fr; gap: 14px 16px; align-items: center;">
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">ltr</span>
<div dir="ltr" style="display: flex; gap: 12px; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="Loading results"></md-loading-indicator>
<span>Loading results…</span>
<md-loading-indicator variant="contained" label="Refreshing"></md-loading-indicator>
</div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">rtl</span>
<div dir="rtl" style="display: flex; gap: 12px; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="جارٍ تحميل النتائج"></md-loading-indicator>
<span>…جارٍ تحميل النتائج</span>
<md-loading-indicator variant="contained" label="جارٍ التحديث"></md-loading-indicator>
</div>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display: grid; grid-template-columns: auto 1fr; gap: 14px 16px; align-items: center;">
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">ltr</span>
<div dir="ltr" style="display: flex; gap: 12px; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="Loading results"></md-loading-indicator>
<span>Loading results…</span>
<md-loading-indicator variant="contained" label="Refreshing"></md-loading-indicator>
</div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">rtl</span>
<div dir="rtl" style="display: flex; gap: 12px; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="جارٍ تحميل النتائج"></md-loading-indicator>
<span>…جارٍ تحميل النتائج</span>
<md-loading-indicator variant="contained" label="جارٍ التحديث"></md-loading-indicator>
</div>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display: grid; grid-template-columns: auto 1fr; gap: 14px 16px; align-items: center;">
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">ltr</span>
<div dir="ltr" style="display: flex; gap: 12px; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="Loading results"></md-loading-indicator>
<span>Loading results…</span>
<md-loading-indicator variant="contained" label="Refreshing"></md-loading-indicator>
</div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">rtl</span>
<div dir="rtl" style="display: flex; gap: 12px; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="جارٍ تحميل النتائج"></md-loading-indicator>
<span>…جارٍ تحميل النتائج</span>
<md-loading-indicator variant="contained" label="جارٍ التحديث"></md-loading-indicator>
</div>
</div>There is no mirror-icon here and nothing to mirror: the morph is radially
symmetric, so the only thing RTL can get wrong is the gap you put between the
indicator and its text. Space it with a logical property and the gap follows
the direction; hard-code margin-right and it lands on the outside edge, with
the label jammed against the shape. Both rows below are dir="rtl":
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: grid; grid-template-columns: auto 1fr; gap: 14px 16px; align-items: center;">
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">correct</span>
<div dir="rtl" style="display: flex; gap: 0; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="جارٍ التحميل" style="margin-inline-end: 12px;"></md-loading-indicator>
<span>…جارٍ تحميل النتائج</span>
</div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">wrong</span>
<div dir="rtl" style="display: flex; gap: 0; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="جارٍ التحميل" style="margin-right: 12px;"></md-loading-indicator>
<span>…جارٍ تحميل النتائج</span>
</div>
</div>import { MdLoadingIndicator } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'grid', gridTemplateColumns: 'auto 1fr', gap: '14px 16px', alignItems: 'center' }}>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace, monospace' }}>correct</span>
<div dir="rtl" style={{ display: 'flex', gap: '0', flexWrap: 'wrap', alignItems: 'center', font: '400 14px/1.4 system-ui, sans-serif' }}>
<MdLoadingIndicator label="جارٍ التحميل" style={{ marginInlineEnd: '12px' }}></MdLoadingIndicator>
<span>…جارٍ تحميل النتائج</span>
</div>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace, monospace' }}>wrong</span>
<div dir="rtl" style={{ display: 'flex', gap: '0', flexWrap: 'wrap', alignItems: 'center', font: '400 14px/1.4 system-ui, sans-serif' }}>
<MdLoadingIndicator label="جارٍ التحميل" style={{ marginRight: '12px' }}></MdLoadingIndicator>
<span>…جارٍ تحميل النتائج</span>
</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: grid; grid-template-columns: auto 1fr; gap: 14px 16px; align-items: center;">
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">correct</span>
<div dir="rtl" style="display: flex; gap: 0; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="جارٍ التحميل" style="margin-inline-end: 12px;"></md-loading-indicator>
<span>…جارٍ تحميل النتائج</span>
</div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">wrong</span>
<div dir="rtl" style="display: flex; gap: 0; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="جارٍ التحميل" style="margin-right: 12px;"></md-loading-indicator>
<span>…جارٍ تحميل النتائج</span>
</div>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display: grid; grid-template-columns: auto 1fr; gap: 14px 16px; align-items: center;">
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">correct</span>
<div dir="rtl" style="display: flex; gap: 0; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="جارٍ التحميل" style="margin-inline-end: 12px;"></md-loading-indicator>
<span>…جارٍ تحميل النتائج</span>
</div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">wrong</span>
<div dir="rtl" style="display: flex; gap: 0; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="جارٍ التحميل" style="margin-right: 12px;"></md-loading-indicator>
<span>…جارٍ تحميل النتائج</span>
</div>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display: grid; grid-template-columns: auto 1fr; gap: 14px 16px; align-items: center;">
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">correct</span>
<div dir="rtl" style="display: flex; gap: 0; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="جارٍ التحميل" style="margin-inline-end: 12px;"></md-loading-indicator>
<span>…جارٍ تحميل النتائج</span>
</div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">wrong</span>
<div dir="rtl" style="display: flex; gap: 0; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="جارٍ التحميل" style="margin-right: 12px;"></md-loading-indicator>
<span>…جارٍ تحميل النتائج</span>
</div>
</div>density is a local override of the inherited data-density. One signal moves
both boxes: the overall size steps 48 → 44 → 40 → 36 → 32px and the shape
inside it 38 → 35 → 32 → 29 → 26px, so the proportion holds at every rung.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: grid; grid-template-columns: auto 1fr; gap: 14px 16px; align-items: center;">
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">0</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="0" label="Loading, rung 0"></md-loading-indicator><md-loading-indicator variant="contained" density="0" label="Loading, rung 0"></md-loading-indicator></div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">-1</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="-1" label="Loading, rung -1"></md-loading-indicator><md-loading-indicator variant="contained" density="-1" label="Loading, rung -1"></md-loading-indicator></div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">-2</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="-2" label="Loading, rung -2"></md-loading-indicator><md-loading-indicator variant="contained" density="-2" label="Loading, rung -2"></md-loading-indicator></div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">-3</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="-3" label="Loading, rung -3"></md-loading-indicator><md-loading-indicator variant="contained" density="-3" label="Loading, rung -3"></md-loading-indicator></div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">-4</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="-4" label="Loading, rung -4"></md-loading-indicator><md-loading-indicator variant="contained" density="-4" label="Loading, rung -4"></md-loading-indicator></div>
</div>import { MdLoadingIndicator } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'grid', gridTemplateColumns: 'auto 1fr', gap: '14px 16px', alignItems: 'center' }}>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace, monospace' }}>0</span>
<div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center' }}><MdLoadingIndicator density="0" label="Loading, rung 0"></MdLoadingIndicator><MdLoadingIndicator variant="contained" density="0" label="Loading, rung 0"></MdLoadingIndicator></div>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace, monospace' }}>-1</span>
<div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center' }}><MdLoadingIndicator density="-1" label="Loading, rung -1"></MdLoadingIndicator><MdLoadingIndicator variant="contained" density="-1" label="Loading, rung -1"></MdLoadingIndicator></div>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace, monospace' }}>-2</span>
<div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center' }}><MdLoadingIndicator density="-2" label="Loading, rung -2"></MdLoadingIndicator><MdLoadingIndicator variant="contained" density="-2" label="Loading, rung -2"></MdLoadingIndicator></div>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace, monospace' }}>-3</span>
<div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center' }}><MdLoadingIndicator density="-3" label="Loading, rung -3"></MdLoadingIndicator><MdLoadingIndicator variant="contained" density="-3" label="Loading, rung -3"></MdLoadingIndicator></div>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace, monospace' }}>-4</span>
<div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center' }}><MdLoadingIndicator density="-4" label="Loading, rung -4"></MdLoadingIndicator><MdLoadingIndicator variant="contained" density="-4" label="Loading, rung -4"></MdLoadingIndicator></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: grid; grid-template-columns: auto 1fr; gap: 14px 16px; align-items: center;">
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">0</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="0" label="Loading, rung 0"></md-loading-indicator><md-loading-indicator variant="contained" density="0" label="Loading, rung 0"></md-loading-indicator></div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">-1</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="-1" label="Loading, rung -1"></md-loading-indicator><md-loading-indicator variant="contained" density="-1" label="Loading, rung -1"></md-loading-indicator></div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">-2</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="-2" label="Loading, rung -2"></md-loading-indicator><md-loading-indicator variant="contained" density="-2" label="Loading, rung -2"></md-loading-indicator></div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">-3</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="-3" label="Loading, rung -3"></md-loading-indicator><md-loading-indicator variant="contained" density="-3" label="Loading, rung -3"></md-loading-indicator></div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">-4</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="-4" label="Loading, rung -4"></md-loading-indicator><md-loading-indicator variant="contained" density="-4" label="Loading, rung -4"></md-loading-indicator></div>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display: grid; grid-template-columns: auto 1fr; gap: 14px 16px; align-items: center;">
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">0</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="0" label="Loading, rung 0"></md-loading-indicator><md-loading-indicator variant="contained" density="0" label="Loading, rung 0"></md-loading-indicator></div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">-1</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="-1" label="Loading, rung -1"></md-loading-indicator><md-loading-indicator variant="contained" density="-1" label="Loading, rung -1"></md-loading-indicator></div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">-2</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="-2" label="Loading, rung -2"></md-loading-indicator><md-loading-indicator variant="contained" density="-2" label="Loading, rung -2"></md-loading-indicator></div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">-3</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="-3" label="Loading, rung -3"></md-loading-indicator><md-loading-indicator variant="contained" density="-3" label="Loading, rung -3"></md-loading-indicator></div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">-4</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="-4" label="Loading, rung -4"></md-loading-indicator><md-loading-indicator variant="contained" density="-4" label="Loading, rung -4"></md-loading-indicator></div>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display: grid; grid-template-columns: auto 1fr; gap: 14px 16px; align-items: center;">
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">0</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="0" label="Loading, rung 0"></md-loading-indicator><md-loading-indicator variant="contained" density="0" label="Loading, rung 0"></md-loading-indicator></div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">-1</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="-1" label="Loading, rung -1"></md-loading-indicator><md-loading-indicator variant="contained" density="-1" label="Loading, rung -1"></md-loading-indicator></div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">-2</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="-2" label="Loading, rung -2"></md-loading-indicator><md-loading-indicator variant="contained" density="-2" label="Loading, rung -2"></md-loading-indicator></div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">-3</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="-3" label="Loading, rung -3"></md-loading-indicator><md-loading-indicator variant="contained" density="-3" label="Loading, rung -3"></md-loading-indicator></div>
<span style="inline-size: 3.5rem; opacity: .65; font-size: .75rem; font-family: ui-monospace, monospace;">-4</span>
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: center;"><md-loading-indicator density="-4" label="Loading, rung -4"></md-loading-indicator><md-loading-indicator variant="contained" density="-4" label="Loading, rung -4"></md-loading-indicator></div>
</div>The two are independent signals, so they compose without any extra wiring — a wrapper sets the rung for everything inside it, and any one indicator can take a tighter rung of its own.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div dir="rtl" data-density="-2" style="display: flex; gap: 16px; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="جارٍ التحميل"></md-loading-indicator>
<md-loading-indicator variant="contained" label="جارٍ التحديث"></md-loading-indicator>
<span>…جارٍ التحميل</span>
<md-loading-indicator density="-4" label="أكثر إحكاما"></md-loading-indicator>
<md-loading-indicator label="افتراضي" style="--md-sys-density-scale: 0;"></md-loading-indicator>
</div>import { MdLoadingIndicator } from '@awc-ui/react';
export function Demo() {
return (
<>
<div dir="rtl" data-density="-2" style={{ display: 'flex', gap: '16px', flexWrap: 'wrap', alignItems: 'center', font: '400 14px/1.4 system-ui, sans-serif' }}>
<MdLoadingIndicator label="جارٍ التحميل"></MdLoadingIndicator>
<MdLoadingIndicator variant="contained" label="جارٍ التحديث"></MdLoadingIndicator>
<span>…جارٍ التحميل</span>
<MdLoadingIndicator density="-4" label="أكثر إحكاما"></MdLoadingIndicator>
<MdLoadingIndicator label="افتراضي" style={{ '--md-sys-density-scale': '0' }}></MdLoadingIndicator>
</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 dir="rtl" data-density="-2" style="display: flex; gap: 16px; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="جارٍ التحميل"></md-loading-indicator>
<md-loading-indicator variant="contained" label="جارٍ التحديث"></md-loading-indicator>
<span>…جارٍ التحميل</span>
<md-loading-indicator density="-4" label="أكثر إحكاما"></md-loading-indicator>
<md-loading-indicator label="افتراضي" style="--md-sys-density-scale: 0;"></md-loading-indicator>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div dir="rtl" data-density="-2" style="display: flex; gap: 16px; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="جارٍ التحميل"></md-loading-indicator>
<md-loading-indicator variant="contained" label="جارٍ التحديث"></md-loading-indicator>
<span>…جارٍ التحميل</span>
<md-loading-indicator density="-4" label="أكثر إحكاما"></md-loading-indicator>
<md-loading-indicator label="افتراضي" style="--md-sys-density-scale: 0;"></md-loading-indicator>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div dir="rtl" data-density="-2" style="display: flex; gap: 16px; flex-wrap: wrap; align-items: center; font: 400 14px/1.4 system-ui, sans-serif;">
<md-loading-indicator label="جارٍ التحميل"></md-loading-indicator>
<md-loading-indicator variant="contained" label="جارٍ التحديث"></md-loading-indicator>
<span>…جارٍ التحميل</span>
<md-loading-indicator density="-4" label="أكثر إحكاما"></md-loading-indicator>
<md-loading-indicator label="افتراضي" style="--md-sys-density-scale: 0;"></md-loading-indicator>
</div>Density — density="-1…-4" locally overrides the inherited data-density
rung; 0 is the default value, not an override. See
Density.
i18n — translate label. It is the accessible name, and the English
default ships silently if you forget.
| Custom property | Purpose | Default |
|---|---|---|
--md-loading-indicator-color | Shape colour | primary, or on-primary-container on contained |
--md-loading-indicator-size | Overall box | 48px (density-scaled) |
--md-loading-indicator-shape-size | Inner morphing shape | 38px (density-scaled) |
--md-loading-indicator-container-color | contained backdrop | primary-container |
--md-loading-indicator-container-shape | contained corner radius | corner-full |
Every one is a plain custom property, so a class, an inline style, or an
ancestor rule all work — there is no themable API beyond the cascade.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<md-loading-indicator label="Tertiary toned" style="--md-loading-indicator-color: var(--md-sys-color-tertiary);"></md-loading-indicator>
<md-loading-indicator label="Error toned" style="--md-loading-indicator-color: var(--md-sys-color-error);"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Brand contained" style="--md-loading-indicator-color: #ffffff; --md-loading-indicator-container-color: #6200ee;"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Squared container" style="--md-loading-indicator-container-color: var(--md-sys-color-secondary-container); --md-loading-indicator-container-shape: 8px;"></md-loading-indicator>
<md-loading-indicator label="Inline override" style="--md-loading-indicator-color: coral;"></md-loading-indicator>import { MdLoadingIndicator } from '@awc-ui/react';
export function Demo() {
return (
<>
<MdLoadingIndicator label="Tertiary toned" style={{ '--md-loading-indicator-color': 'var(--md-sys-color-tertiary)' }}></MdLoadingIndicator>
<MdLoadingIndicator label="Error toned" style={{ '--md-loading-indicator-color': 'var(--md-sys-color-error)' }}></MdLoadingIndicator>
<MdLoadingIndicator variant="contained" label="Brand contained" style={{ '--md-loading-indicator-color': '#ffffff', '--md-loading-indicator-container-color': '#6200ee' }}></MdLoadingIndicator>
<MdLoadingIndicator variant="contained" label="Squared container" style={{ '--md-loading-indicator-container-color': 'var(--md-sys-color-secondary-container)', '--md-loading-indicator-container-shape': '8px' }}></MdLoadingIndicator>
<MdLoadingIndicator label="Inline override" style={{ '--md-loading-indicator-color': 'coral' }}></MdLoadingIndicator>
</>
);
}// 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-loading-indicator label="Tertiary toned" style="--md-loading-indicator-color: var(--md-sys-color-tertiary);"></md-loading-indicator>
<md-loading-indicator label="Error toned" style="--md-loading-indicator-color: var(--md-sys-color-error);"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Brand contained" style="--md-loading-indicator-color: #ffffff; --md-loading-indicator-container-color: #6200ee;"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Squared container" style="--md-loading-indicator-container-color: var(--md-sys-color-secondary-container); --md-loading-indicator-container-shape: 8px;"></md-loading-indicator>
<md-loading-indicator label="Inline override" style="--md-loading-indicator-color: coral;"></md-loading-indicator><script setup>
import '@awc-ui/core/define';
</script>
<template>
<md-loading-indicator label="Tertiary toned" style="--md-loading-indicator-color: var(--md-sys-color-tertiary);"></md-loading-indicator>
<md-loading-indicator label="Error toned" style="--md-loading-indicator-color: var(--md-sys-color-error);"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Brand contained" style="--md-loading-indicator-color: #ffffff; --md-loading-indicator-container-color: #6200ee;"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Squared container" style="--md-loading-indicator-container-color: var(--md-sys-color-secondary-container); --md-loading-indicator-container-shape: 8px;"></md-loading-indicator>
<md-loading-indicator label="Inline override" style="--md-loading-indicator-color: coral;"></md-loading-indicator>
</template><script>
import '@awc-ui/core/define';
</script>
<md-loading-indicator label="Tertiary toned" style="--md-loading-indicator-color: var(--md-sys-color-tertiary);"></md-loading-indicator>
<md-loading-indicator label="Error toned" style="--md-loading-indicator-color: var(--md-sys-color-error);"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Brand contained" style="--md-loading-indicator-color: #ffffff; --md-loading-indicator-container-color: #6200ee;"></md-loading-indicator>
<md-loading-indicator variant="contained" label="Squared container" style="--md-loading-indicator-container-color: var(--md-sys-color-secondary-container); --md-loading-indicator-container-shape: 8px;"></md-loading-indicator>
<md-loading-indicator label="Inline override" style="--md-loading-indicator-color: coral;"></md-loading-indicator>CSS part — shape, the morphing element itself. Use it for what a colour
token cannot express: opacity, or a filter.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<style>
.low-opacity::part(shape) { opacity: 0.87; }
.shadow-shape::part(shape) { filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3)); }
</style>
<md-loading-indicator class="low-opacity" label="Reduced opacity"></md-loading-indicator>
<md-loading-indicator class="shadow-shape" label="Drop shadow"></md-loading-indicator>import { MdLoadingIndicator } from '@awc-ui/react';
export function Demo() {
return (
<>
<style>
.low-opacity::part(shape) { opacity: 0.87; }
.shadow-shape::part(shape) { filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3)); }
</style>
<MdLoadingIndicator className="low-opacity" label="Reduced opacity"></MdLoadingIndicator>
<MdLoadingIndicator className="shadow-shape" label="Drop shadow"></MdLoadingIndicator>
</>
);
}// 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>
.low-opacity::part(shape) { opacity: 0.87; }
.shadow-shape::part(shape) { filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3)); }
</style>
<md-loading-indicator class="low-opacity" label="Reduced opacity"></md-loading-indicator>
<md-loading-indicator class="shadow-shape" label="Drop shadow"></md-loading-indicator><script setup>
import '@awc-ui/core/define';
</script>
<template>
<style>
.low-opacity::part(shape) { opacity: 0.87; }
.shadow-shape::part(shape) { filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3)); }
</style>
<md-loading-indicator class="low-opacity" label="Reduced opacity"></md-loading-indicator>
<md-loading-indicator class="shadow-shape" label="Drop shadow"></md-loading-indicator>
</template><script>
import '@awc-ui/core/define';
</script>
<style>
.low-opacity::part(shape) { opacity: 0.87; }
.shadow-shape::part(shape) { filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3)); }
</style>
<md-loading-indicator class="low-opacity" label="Reduced opacity"></md-loading-indicator>
<md-loading-indicator class="shadow-shape" label="Drop shadow"></md-loading-indicator>md-loading-indicator::part(shape) { opacity: 0.87; filter: drop-shadow(0 2px 4px rgb(0 0 0 / 0.3));}md-progress-indicator ·
md-skeleton ·
md-select ·
md-multi-select ·
md-autocomplete ·
md-search
md-loading-indicatorTwo 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-loading-indicator 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.