Spinner
Shows that something is loading.
- v1.0.0
- SSR
- Zoneless
- 0.4 kB gzip
import { Component } from '@angular/core';
import { NdIcon } from '@ndop/core';
import { Spinner } from '@/ui/spinner/spinner';
/** Spinners in three sizes. */
@Component({
selector: 'example-spinner-demo',
imports: [NdIcon, Spinner],
template: `
<div class="flex items-center gap-6">
<span ndSpinner><svg ndIcon="loader-circle"></svg></span>
<span ndSpinner class="size-6"><svg ndIcon="loader-circle"></svg></span>
<span ndSpinner label="Loading results" class="size-8">
<svg ndIcon="loader-circle"></svg>
</span>
</div>
`,
})
export class SpinnerDemoExample {}
A spinner shows that something is loading when you can't say how far it
has got. ndSpinner spins what's inside it, usually the loader-circle
icon, and announces itself as a status named "Loading", or what its
label says.
Installation
npx @ndop/cli add spinnerpnpm dlx @ndop/cli add spinneryarn dlx @ndop/cli add spinnerbunx @ndop/cli add spinnerInstall the dependencies
npm install @ndop/corepnpm add @ndop/coreyarn add @ndop/corebun add @ndop/coreCopy the code into your project
At the paths your
ndop.jsonaliases point to; these use the defaults.src/app/ui/spinner/spinner.tsimport { computed, Directive, input } from '@angular/core'; import { cn } from '@/lib/utils'; /** * A spinning loading indicator, announced as a status. Put the loading * icon inside it: the icon stays hidden from assistive technology, and the * spinner carries the name. * * @example * ```html * <span ndSpinner><svg ndIcon="loader-circle"></svg></span> * ``` */ @Directive({ selector: '[ndSpinner]', host: { 'data-slot': 'spinner', role: 'status', '[attr.aria-label]': 'label()', '[class]': 'classes()', }, }) export class Spinner { /** What is loading, read by screen readers. */ readonly label = input('Loading'); /** Extra classes, merged last so they win. */ readonly class = input(''); protected readonly classes = computed(() => cn('size-4 animate-spin', 'inline-flex [&>svg]:size-full', this.class()), ); }src/app/lib/utils.ts/** * Class helpers used by every styled item. They come from `@ndop/core`; * this file is yours, so it is the place to customize them, for example by * wrapping `cn` with an extended tailwind-merge configuration for your own * utilities. * * @packageDocumentation */ export { cn, variants, type ClassValue, type VariantOf } from '@ndop/core';Update the import paths to match your project
The files import each other through the
@/uiand@/libaliases.
Usage
import { Spinner } from '@/ui/spinner/spinner';<div class="flex items-center gap-6">
<span ndSpinner><svg ndIcon="loader-circle"></svg></span>
<span ndSpinner class="size-6"><svg ndIcon="loader-circle"></svg></span>
<span ndSpinner label="Loading results" class="size-8">
<svg ndIcon="loader-circle"></svg>
</span>
</div>Examples
Spinner button
A button that shows a spinner while it saves.
import { Component, signal } from '@angular/core';
import { NdIcon } from '@ndop/core';
import { Button } from '@/ui/button/button';
import { Spinner } from '@/ui/spinner/spinner';
/**
* A button that shows a spinner, and is disabled, while its action runs.
*/
@Component({
selector: 'example-spinner-button',
imports: [Button, NdIcon, Spinner],
template: `
<button ndButton [disabled]="saving()" (click)="save()">
@if (saving()) {
<span ndSpinner label="Saving"><svg ndIcon="loader-circle"></svg></span>
Saving…
} @else {
Save changes
}
</button>
`,
})
export class SpinnerButtonExample {
protected readonly saving = signal(false);
/** Pretends to save for two seconds. */
protected save(): void {
this.saving.set(true);
setTimeout(() => this.saving.set(false), 2000);
}
}
Accessibility
Spinner has no keyboard interaction or focus handling of its own; it keeps the semantics of the element it's on.
API reference
Spinner
[ndSpinner]A spinning loading indicator, announced as a status. Put the loading icon inside it: the icon stays hidden from assistive technology, and the spinner carries the name.
| Spinner binding | Type | Default |
|---|---|---|
[label]What is loading, read by screen readers. | string | 'Loading' |
[class]Extra classes, merged last so they win. | string | '' |
| Data attribute | Values |
|---|---|
data-slot | spinner |
Agent notes
Do
- Say what's loading with
label, such as "Saving changes". - Put it in a disabled button while that button's action runs, next to the button's text.
- Use Progress instead when you know how far the task has got.
Don't
- Don't show several spinners for one task.
- Don't use it for anything that takes more than a few seconds without saying what's happening.