Container for managing multiple progress bars simultaneously with coordinated rendering, event-driven updates, and logging capabilities. The MultiBar class enables complex progress visualization scenarios with multiple concurrent tasks.
Creates a new multi-progress bar container. Individual bars must be added using the create method.
/**
* Creates a new multi-progress bar container
* Note: MultiBar automatically disables synchronousUpdate regardless of options
* @param options - Global configuration options applied to all bars
* @param preset - Preset configuration to merge with options
*/
class MultiBar extends EventEmitter {
constructor(options?: ProgressBarOptions, preset?: PresetConfiguration);
}Usage Examples:
const cliProgress = require('cli-progress');
// Basic multi-bar container
const multibar = new cliProgress.MultiBar({
clearOnComplete: false,
hideCursor: true
});
// Multi-bar with custom format and preset
const multibar2 = new cliProgress.MultiBar({
format: ' {bar} | {filename} | {value}/{total}',
hideCursor: true,
clearOnComplete: false
}, cliProgress.Presets.shades_grey);Adds a new progress bar to the container and starts it immediately. Returns a SingleBar instance for individual control.
/**
* Creates and adds a new progress bar to the container
* @param total - Maximum value for the progress bar
* @param startValue - Initial progress value (default: 0)
* @param payload - Custom data for token replacement
* @param barOptions - Per-bar options to override global settings
* @returns SingleBar instance for individual control
*/
create(total: number, startValue?: number, payload?: object, barOptions?: object): SingleBar;Usage Examples:
// Create basic progress bars
const bar1 = multibar.create(100, 0);
const bar2 = multibar.create(200, 0);
// Create with initial payload
const bar3 = multibar.create(150, 0, {
filename: 'data.csv',
status: 'processing'
});
// Create with custom options for this bar only
const bar4 = multibar.create(300, 0, { task: 'upload' }, {
format: 'Uploading |{bar}| {percentage}% | {task}',
barCompleteChar: '▓',
barIncompleteChar: '░'
});Removes a specific progress bar from the container and updates the display.
/**
* Removes a progress bar from the container
* @param bar - The SingleBar instance to remove
* @returns true if successfully removed, false if not found
*/
remove(bar: SingleBar): boolean;Usage Examples:
const bar1 = multibar.create(100, 0);
const bar2 = multibar.create(200, 0);
// Complete and remove first bar
bar1.update(100);
const removed = multibar.remove(bar1);
console.log(`Bar removed: ${removed}`); // true
// Continue with remaining bars
bar2.update(150);Stops all progress bars in the container and performs cleanup.
/**
* Stops all progress bars and performs cleanup
*/
stop(): void;Usage Examples:
// Stop all bars when complete
multibar.stop();
// Emergency stop (e.g., on error)
try {
// ... processing
} catch (error) {
multibar.stop();
throw error;
}Outputs buffered content above the progress bars during operation, useful for logging events or status messages.
/**
* Outputs content above progress bars
* @param message - Message to display (must include newline)
*/
log(message: string): void;Usage Examples:
// Log individual events
multibar.log('Started processing batch 1\n');
multibar.log('Warning: File not found, skipping\n');
multibar.log('Completed batch 1 successfully\n');
// Log with timestamp
const timestamp = new Date().toISOString();
multibar.log(`[${timestamp}] Processing started\n`);MultiBar extends EventEmitter and emits comprehensive events for monitoring progress lifecycle:
// Event: 'start' - Emitted when first bar is created
multibar.on('start', () => {
console.log('Multi-bar progress started');
});
// Event: 'update-pre' - Emitted before each update cycle
multibar.on('update-pre', () => {
// Pre-update operations
});
// Event: 'redraw-pre' - Emitted before redrawing bars
multibar.on('redraw-pre', () => {
// Pre-redraw operations
});
// Event: 'redraw-post' - Emitted after redrawing bars
multibar.on('redraw-post', () => {
// Post-redraw operations
});
// Event: 'update-post' - Emitted after each update cycle
multibar.on('update-post', () => {
// Post-update operations
});
// Event: 'stop-pre-clear' - Emitted before clearing on stop
multibar.on('stop-pre-clear', () => {
// Pre-clear operations
});
// Event: 'stop' - Emitted when all bars are stopped
multibar.on('stop', () => {
console.log('Multi-bar progress completed');
});interface MultiBarProperties {
readonly bars: SingleBar[]; // Array of managed progress bars
readonly isActive: boolean; // Whether any bars are active
readonly options: ProgressBarOptions; // Global configuration options
}const cliProgress = require('cli-progress');
const fs = require('fs').promises;
async function processFiles(filePaths) {
const multibar = new cliProgress.MultiBar({
format: ' {bar} | {filename} | {percentage}% | {value}/{total} KB',
hideCursor: true,
clearOnComplete: false,
stopOnComplete: true
}, cliProgress.Presets.shades_classic);
const progressBars = new Map();
// Create progress bar for each file
for (const filePath of filePaths) {
const stats = await fs.stat(filePath);
const bar = multibar.create(Math.ceil(stats.size / 1024), 0, {
filename: path.basename(filePath)
});
progressBars.set(filePath, bar);
}
// Process files concurrently
await Promise.all(filePaths.map(async (filePath) => {
const bar = progressBars.get(filePath);
await processFile(filePath, (bytesProcessed) => {
bar.update(Math.ceil(bytesProcessed / 1024));
});
}));
multibar.stop();
}const multibar = new cliProgress.MultiBar({
format: ' {bar} | Task {id} | {status}',
hideCursor: true
});
const activeBars = new Map();
let taskId = 0;
function startTask(taskSize) {
const id = ++taskId;
const bar = multibar.create(taskSize, 0, {
id: id,
status: 'starting'
});
activeBars.set(id, bar);
// Simulate task progress
const interval = setInterval(() => {
const currentValue = bar.value;
if (currentValue >= taskSize) {
clearInterval(interval);
bar.update(taskSize, { status: 'completed' });
// Remove completed bar after delay
setTimeout(() => {
multibar.remove(bar);
activeBars.delete(id);
// Stop if all tasks complete
if (activeBars.size === 0) {
multibar.stop();
}
}, 1000);
} else {
bar.increment(Math.random() * 5, {
status: 'processing'
});
}
}, 100);
return id;
}
// Start multiple tasks
startTask(100);
startTask(150);
startTask(80);const multibar = new cliProgress.MultiBar({
format: ' {bar} | {filename} | {status}',
gracefulExit: true
});
async function processWithLogging(files) {
const bars = new Map();
try {
// Create bars for each file
files.forEach((file, index) => {
const bar = multibar.create(100, 0, {
filename: file.name,
status: 'queued'
});
bars.set(file.id, bar);
});
multibar.log(`Starting processing of ${files.length} files\n`);
for (const file of files) {
const bar = bars.get(file.id);
try {
bar.update(0, { status: 'processing' });
await processFile(file, (progress) => {
bar.update(progress);
});
bar.update(100, { status: 'completed' });
multibar.log(`✓ Completed: ${file.name}\n`);
} catch (error) {
bar.update(bar.value, { status: 'failed' });
multibar.log(`✗ Failed: ${file.name} - ${error.message}\n`);
}
}
} finally {
multibar.stop();
}
}const multibar = new cliProgress.MultiBar({
format: ' {bar} | {operation} | {percentage}% | ETA: {eta}s'
});
async function performConcurrentOperations() {
const operations = [
{ name: 'Download', steps: 100 },
{ name: 'Extract', steps: 50 },
{ name: 'Process', steps: 200 }
];
const bars = operations.map(op =>
multibar.create(op.steps, 0, { operation: op.name })
);
// Run operations concurrently
await Promise.all(operations.map(async (op, index) => {
const bar = bars[index];
for (let step = 0; step <= op.steps; step++) {
await new Promise(resolve => setTimeout(resolve, 50));
bar.update(step);
}
}));
multibar.stop();
}