unicode-spinner
v1.0.0
Published
ASCII and Unicode animated spinners for Node.js terminals and browsers. One class, 25+ built-in frame sequences — braille, classic pipe, dots, arrows, bars, moon, clock, emoji and more.
Maintainers
Readme
unicode-spinner
ASCII and Unicode animated spinners for Node.js terminals and browsers.
One class, 24 built-in frame sequences, zero dependencies.
⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏ ← braille (Claude style)
| / - \ ← classic pipe
. .. ... ← dots
◐ ◓ ◑ ◒ ← circle
← ↖ ↑ ↗ → ↘ ↓ ↙ ← arrows
▁ ▂ ▃ ▄ ▅ ▆ ▇ █ ← grow
🌑 🌒 🌓 🌔 🌕 🌖 🌗 🌘 ← moonInstallation
npm install unicode-spinnerQuick start
Node.js terminal
import { Spinner } from 'unicode-spinner';
const s = Spinner.braille({ text: 'Loading…' });
s.start();
await doWork();
s.succeed('Done!'); // ✔ Done!
// s.fail('Oops!'); // ✖ Oops!
// s.warn('Slow…'); // ⚠ Slow…
// s.info('FYI'); // ℹ FYIReact hook
import { Spinner, SpinnerName } from 'unicode-spinner';
import { useMemo, useState, useEffect } from 'react';
function useSpinner(name: SpinnerName = 'braille'): string {
const spinner = useMemo(() => new Spinner({ frames: name }), [name]);
const [frame, setFrame] = useState(spinner.currentFrame);
useEffect(() => {
const unsub = spinner.subscribe(setFrame);
spinner.startFrames();
return () => { spinner.stopFrames(); unsub(); };
}, [spinner]);
return frame;
}
// Usage:
function LoadingButton({ busy }: { busy: boolean }) {
const frame = useSpinner('moon');
return <button>{busy ? `${frame} Loading` : 'Submit'}</button>;
}Custom frames
import { Spinner } from 'unicode-spinner';
// Any string array works — Unicode, emoji, ASCII, whatever:
const s = new Spinner({
frames: ['🔴', '🟠', '🟡', '🟢', '🔵', '🟣'],
interval: 150,
text: 'Cycling colors…',
});
s.start();All built-in spinners
| Name | Frames | Default interval |
|---|---|---|
| braille | ⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏ | 80 ms |
| brailleFull | ⣾⣽⣻⢿⡿⣟⣯⣷ | 80 ms |
| brailleQuarter | ⠁⠂⠄⠂ | 100 ms |
| snake | ⠈⠐⠠⢀⡀⠄⠂⠁ | 80 ms |
| line | \| / - \\ | 120 ms |
| pipe | ┤┘┴└├┌┬┐ | 120 ms |
| dots | . .. ... | 300 ms |
| dotsBounce | ●○○ ○●○ ○○● | 200 ms |
| dot | · • · | 400 ms |
| circle | ◐◓◑◒ | 120 ms |
| triangle | ◢◣◤◥ | 120 ms |
| box | ▖▘▝▗ | 120 ms |
| square | ◰◳◲◱ | 120 ms |
| bowtie | ⊣⊤⊢⊥ | 120 ms |
| hourglass | ⧗⧖ | 400 ms |
| arrows | ← ↖ ↑ ↗ → ↘ ↓ ↙ | 100 ms |
| arrowsBold | ⇐⇑⇒⇓ | 120 ms |
| bar | ▏▎▍▌▋▊▉█▉▊… | 60 ms |
| grow | ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁ | 60 ms |
| pulse | █▓▒░▒▓ | 100 ms |
| moon | 🌑🌒🌓🌔🌕🌖🌗🌘 | 120 ms |
| clock | 🕛🕐🕑🕒…🕚 | 100 ms |
| earth | 🌍🌎🌏 | 200 ms |
| star | ✶✸✹✺✹✷ | 120 ms |
Access frame arrays directly via the SPINNERS object:
import { SPINNERS } from 'unicode-spinner';
console.log(SPINNERS.braille); // ['⠋', '⠙', '⠹', ...]API
new Spinner(options)
| Option | Type | Default | Description |
|---|---|---|---|
| frames | SpinnerName \| string[] | — | Built-in name or custom array |
| interval | number | sequence default | Milliseconds per frame |
| text | string | '' | Label shown in terminal mode |
| stream | NodeJS.WriteStream | process.stdout | Output stream |
Terminal methods
| Method | Description |
|---|---|
| .start(text?) | Start spinner, hide cursor |
| .stop() | Stop and clear line |
| .succeed(text?) | Stop with ✔ |
| .fail(text?) | Stop with ✖ |
| .warn(text?) | Stop with ⚠ |
| .info(text?) | Stop with ℹ |
Framework-agnostic methods
| Method | Description |
|---|---|
| .startFrames(text?) | Start timer, no terminal writes |
| .stopFrames() | Stop timer |
| .subscribe(cb) | Register frame callback, returns unsubscribe fn |
| .nextFrame() | Advance and return next frame string |
| .currentFrame | Current frame string (getter, no advance) |
| .isSpinning | true while timer is active |
CommonJS usage
const { Spinner } = require('unicode-spinner');
const s = Spinner.braille({ text: 'Loading…' });
s.start();Contributing
Contributions welcome! Open an issue or PR on GitHub.
License
MIT © Tekeshwar Singh
