A lightweight, animated, themeable CLI progress bar for Node.js.
Zero config to start — full customization when needed.
- 🎨 6 built-in themes — default, minimal, retro, blocks, dots, arrows
- ♿ Colorblind-friendly palettes — deuteranopia, protanopia, tritanopia
- 🎭 Custom JSON themes — load your own theme from a file
- ✨ Smooth animation — animated fill with configurable speed
- 📦 Tiny footprint — only 2 dependencies (
chalk,cli-cursor)
npm install progressimoimport ProgressBar from 'progressimo';
// Zero config — works out of the box
const bar = new ProgressBar({ total: 100 });
bar.update(50); // 50% done
bar.complete(); // jump to 100%, clean upThat's it — two lines to get a working progress bar.
default [████████████████████░░░░░░░░░░] 60%
minimal [##################------------] 60%
retro [=================>------------] 60%
blocks [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░] 60%
dots [••••••••••••••••••············] 60%
arrows [▸▸▸▸▸▸▸▸▸▸▸▸▸▸▸▸▸▸▹▹▹▹▹▹▹▹▹▹▹▹] 60%
import ProgressBar from 'progressimo';
const bar = new ProgressBar({ total: 100, theme: 'retro' });
bar.update(60);
// retro [===============>--------------] 60%const bar = new ProgressBar({
total: 100,
palette: 'deuteranopia', // blue + orange — safe for red/green CVD
});
bar.update(75);const bar = new ProgressBar({
total: 100,
width: 40,
label: 'Uploading',
fill: '▰',
empty: '▱',
color: 'magentaBright',
});
bar.update(30);
// Uploading [▰▰▰▰▰▰▰▰▰▰▰▰▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱] 30%Create a JSON file like themes/my-theme.json:
{
"fill": "★",
"empty": "☆",
"head": "",
"leftBracket": "[",
"rightBracket": "]",
"color": "yellow"
}Then use it:
const bar = new ProgressBar({
total: 100,
theme: './themes/my-theme.json',
});
bar.update(50);
// [★★★★★★★★★★★★★★★☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆] 50%const bar = new ProgressBar({ total: 100, label: 'Installing' });
// The bar will smoothly slide from 0 → 80 instead of jumping
bar.update(80, { animate: true });import ProgressBar from 'progressimo';
async function downloadFiles(files) {
const bar = new ProgressBar({
total: files.length,
label: 'Downloading',
theme: 'dots',
});
for (let i = 0; i < files.length; i++) {
await downloadFile(files[i]);
bar.update(i + 1);
}
bar.complete();
}const bar = new ProgressBar({ total: 200 });
bar.increment(); // 1/200
bar.increment(10); // 11/200
bar.increment(); // 12/200
bar.complete(); // 200/200, done| Option | Type | Default | Description |
|---|---|---|---|
total |
number |
100 |
Value that represents 100% |
theme |
string |
'default' |
Built-in theme name or path to a .json theme file |
palette |
string |
— | Colorblind palette: 'deuteranopia', 'protanopia', 'tritanopia' |
width |
number |
30 |
Character width of the bar (excluding brackets/label) |
label |
string |
'' |
Text label before the bar |
fill |
string |
'█' |
Fill character (overrides theme) |
empty |
string |
'░' |
Empty character (overrides theme) |
head |
string |
'' |
Leading edge character (overrides theme) |
color |
string |
'cyan' |
Chalk color name for the filled portion |
animationInterval |
number |
50 |
Milliseconds between frames during smooth animation |
stream |
WriteStream |
process.stderr |
Output stream |
| Theme | Fill | Empty | Head | Color |
|---|---|---|---|---|
default |
█ |
░ |
— | cyan |
minimal |
# |
- |
— | white |
retro |
= |
- |
> |
green |
blocks |
▓ |
░ |
— | magenta |
dots |
• |
· |
— | yellow |
arrows |
▸ |
▹ |
— | blue |
These palettes remap colors to combinations that are distinguishable for people with color vision deficiencies.
| Palette | Fill Color | Empty Color | Target |
|---|---|---|---|
deuteranopia |
blue | bright yellow | Reduced green sensitivity (most common) |
protanopia |
bright blue | yellow | Reduced red sensitivity |
tritanopia |
red | bright cyan | Reduced blue sensitivity |
Create a new progress bar instance. All options are optional — zero config works out of the box.
Set progress to an absolute value (clamped to 0–total).
Pass { animate: true } for smooth animation.
Add delta (default 1) to the current progress.
Jump to 100%, render the final frame, restore the cursor, and print a newline.
import { themes, palettes } from 'progressimo';
console.log(Object.keys(themes));
// ['default', 'minimal', 'retro', 'blocks', 'dots', 'arrows']
console.log(palettes.deuteranopia);
// { fill: 'blue', empty: 'yellowBright', label: 'white', percentage: 'blueBright' }Run the interactive demo that cycles through all themes and palettes:
npx progressimo-demo
# or
node node_modules/progressimo/bin/demo.jsThe "animation" trick is simple: instead of printing new lines, we overwrite the same terminal line on every update.
readline.cursorTo(stream, 0)— moves the cursor back to column 0readline.clearLine(stream, 0)— erases the current linestream.write(barString)— writes the new bar
Because we never print a \n, the cursor stays on the same line. cli-cursor hides the blinking cursor during animation for a clean look.
Progress output goes to stderr by default so stdout stays clean for piping.
# Login to your npm account
npm login
# Publish (first time)
npm publish
# After making changes, bump the version
npm version patch # 1.0.0 → 1.0.1
npm publishKey concepts:
"main"in package.json tells Node.js which file to load onimport"bin"registers CLI commands (likeprogressimo-demo)"type": "module"enables ES Module syntax (import/export)"files"controls which files are included in the published tarball
- Fork the repo
- Create a feature branch (
git checkout -b feature/my-theme) - Commit your changes (
git commit -m 'Add new theme') - Push to the branch (
git push origin feature/my-theme) - Open a Pull Request
MIT