Top Related Projects
A high-level terminal interface library for node.js.
Minimalist Go package aimed at creating Console User Interfaces.
Golang terminal dashboard
simple terminal UI for git commands
A powerful little TUI framework 🏗
Build terminal user interfaces and dashboards using Rust
Quick Overview
Blessed-contrib is a Node.js library that builds on top of the blessed library to create beautiful terminal dashboards using ASCII art and Unicode characters. It provides a collection of widgets and charts that can be easily composed to create rich, interactive command-line interfaces and dashboards.
Pros
- Offers a wide variety of pre-built widgets and charts for terminal-based dashboards
- Provides an easy-to-use API for creating complex layouts and arrangements
- Supports real-time updates and animations
- Highly customizable with extensive styling options
Cons
- Limited to terminal environments, not suitable for GUI applications
- May have performance issues with large datasets or complex layouts
- Learning curve for users unfamiliar with blessed or terminal-based interfaces
- Some widgets may not render correctly in all terminal emulators
Code Examples
Creating a simple dashboard with a line chart:
const blessed = require('blessed');
const contrib = require('blessed-contrib');
const screen = blessed.screen();
const grid = new contrib.grid({rows: 1, cols: 1, screen: screen});
const line = grid.set(0, 0, 1, 1, contrib.line, {
style: {line: "yellow", text: "green", baseline: "black"},
xLabelPadding: 3,
xPadding: 5,
label: 'Sales Growth'
});
const data = {
x: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
y: [10, 15, 25, 30, 35, 40]
};
line.setData([data]);
screen.key(['escape', 'q', 'C-c'], function(ch, key) {
return process.exit(0);
});
screen.render();
Adding a map widget to the dashboard:
const map = grid.set(0, 1, 1, 1, contrib.map, {label: 'World Map'});
const data = [
{lat: 37.5, lon: -122.1, color: "red", char: "X"}
];
map.setData(data);
Creating a log widget:
const log = grid.set(1, 0, 1, 2, contrib.log, {
fg: "green",
selectedFg: "green",
label: 'Server Log'
});
log.log("System started");
log.log("Listening on port 8080");
Getting Started
To get started with blessed-contrib:
-
Install the library:
npm install blessed blessed-contrib
-
Create a new JavaScript file (e.g.,
dashboard.js
) and import the required modules:const blessed = require('blessed'); const contrib = require('blessed-contrib');
-
Create a screen and grid:
const screen = blessed.screen(); const grid = new contrib.grid({rows: 2, cols: 2, screen: screen});
-
Add widgets to the grid and render the screen:
const line = grid.set(0, 0, 1, 2, contrib.line, {label: 'Line Chart'}); // Add data to the line chart screen.render();
-
Run your dashboard:
node dashboard.js
Competitor Comparisons
A high-level terminal interface library for node.js.
Pros of blessed
- More mature and stable project with a larger user base
- Provides a lower-level API for greater flexibility and control
- Better documentation and more extensive examples
Cons of blessed
- Steeper learning curve for beginners
- Requires more code to create complex layouts and widgets
- Less out-of-the-box functionality for creating dashboards
Code Comparison
blessed:
const blessed = require('blessed');
const screen = blessed.screen();
const box = blessed.box({
content: 'Hello, world!'
});
screen.append(box);
blessed-contrib:
const contrib = require('blessed-contrib');
const screen = contrib.screen();
const grid = new contrib.grid({rows: 1, cols: 1});
const box = grid.set(0, 0, 1, 1, contrib.box, {content: 'Hello, world!'});
screen.render();
Summary
blessed is a more flexible and powerful library for creating terminal-based user interfaces, offering greater control and customization options. It's ideal for developers who need fine-grained control over their UI elements.
blessed-contrib, built on top of blessed, provides a higher-level API with pre-built widgets and layouts, making it easier to create complex dashboards and data visualizations quickly. It's more suitable for rapid prototyping and creating data-rich terminal applications with less code.
Both libraries have their strengths, and the choice between them depends on the specific requirements of your project and your familiarity with terminal-based UI development.
Minimalist Go package aimed at creating Console User Interfaces.
Pros of gocui
- Written in Go, offering better performance and lower resource usage
- Simpler API, making it easier to create basic terminal user interfaces
- Focuses on core TUI functionality without extra widgets or charts
Cons of gocui
- Less feature-rich compared to blessed-contrib's extensive widget library
- Limited to terminal-based interfaces, while blessed-contrib can create web-based dashboards
- Lacks built-in support for complex data visualizations like graphs and charts
Code Comparison
gocui example:
g, err := gocui.NewGui(gocui.OutputNormal)
if err != nil {
log.Panicln(err)
}
defer g.Close()
g.SetManagerFunc(layout)
blessed-contrib example:
var blessed = require('blessed')
, contrib = require('blessed-contrib')
, screen = blessed.screen()
, grid = new contrib.grid({rows: 12, cols: 12, screen: screen})
The gocui example demonstrates its simplicity in creating a basic GUI, while the blessed-contrib example showcases its grid-based layout system for more complex dashboards.
Golang terminal dashboard
Pros of termui
- Written in Go, offering better performance and easier deployment
- More actively maintained with recent updates
- Simpler API and easier to get started with
Cons of termui
- Less extensive widget library compared to blessed-contrib
- Limited to terminal-based applications, while blessed-contrib can be used in web browsers
Code Comparison
blessed-contrib (JavaScript):
var blessed = require('blessed');
var contrib = require('blessed-contrib');
var screen = blessed.screen();
var grid = new contrib.grid({rows: 12, cols: 12, screen: screen});
grid.set(0, 0, 4, 4, contrib.line, {label: 'Stocks'});
termui (Go):
ui := termui.New()
defer ui.Close()
p := widgets.NewParagraph()
p.Text = "Hello World!"
ui.Render(p)
Both libraries provide ways to create terminal-based user interfaces, but termui's approach is more straightforward and idiomatic to Go, while blessed-contrib offers more flexibility and a wider range of widgets in JavaScript.
simple terminal UI for git commands
Pros of lazygit
- Focused specifically on Git operations, providing a more streamlined and intuitive interface for Git users
- Offers interactive staging, commit management, and branch operations within a single TUI
- Regularly updated with new features and improvements
Cons of lazygit
- Limited to Git functionality, lacking the versatility of blessed-contrib for creating various dashboard components
- Steeper learning curve for users not familiar with Git concepts
- Less customizable in terms of layout and visual elements compared to blessed-contrib
Code Comparison
lazygit (Go):
func (gui *Gui) handleCommitConfirm(g *gocui.Gui, v *gocui.View) error {
message := gui.trimmedContent(v)
if message == "" {
return gui.createErrorPanel(gui.Tr.NoCommitMessageErr)
}
return gui.handleCommitSubmit(message)
}
blessed-contrib (JavaScript):
function line(options) {
if (!(this instanceof Line)) {
return new Line(options)
}
options = options || {}
this.options = options
this.type = 'line'
this.data = []
}
While both repositories provide terminal-based user interfaces, lazygit focuses on Git operations with a more opinionated design, whereas blessed-contrib offers a flexible framework for creating various dashboard components. The code snippets illustrate the different languages and approaches used in each project.
A powerful little TUI framework 🏗
Pros of Bubbletea
- Written in Go, offering better performance and concurrency support
- More flexible and customizable, allowing for complex TUI applications
- Active development with frequent updates and a growing community
Cons of Bubbletea
- Steeper learning curve, especially for developers new to Go
- Less out-of-the-box components compared to Blessed-contrib
Code Comparison
Blessed-contrib example:
var blessed = require('blessed')
var contrib = require('blessed-contrib')
var screen = blessed.screen()
var grid = new contrib.grid({rows: 12, cols: 12, screen: screen})
grid.set(0, 0, 4, 4, contrib.line, {label: 'Stocks'})
Bubbletea example:
import (
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
)
type model struct {
viewport viewport.Model
}
func (m model) Init() tea.Cmd {
return nil
}
Both libraries offer powerful tools for creating terminal user interfaces, but they cater to different needs and preferences. Blessed-contrib provides a rich set of pre-built components and is easier to get started with, especially for JavaScript developers. Bubbletea, on the other hand, offers more flexibility and performance, making it suitable for complex applications, but requires more setup and Go knowledge.
Build terminal user interfaces and dashboards using Rust
Pros of tui-rs
- Written in Rust, offering better performance and memory safety
- More flexible and customizable, allowing for complex terminal UIs
- Actively maintained with regular updates and improvements
Cons of tui-rs
- Steeper learning curve, especially for developers not familiar with Rust
- Less out-of-the-box widgets compared to blessed-contrib
Code Comparison
tui-rs:
use tui::widgets::{Block, Borders};
let block = Block::default()
.title("Block")
.borders(Borders::ALL);
f.render_widget(block, chunks[0]);
blessed-contrib:
var blessed = require('blessed');
var contrib = require('blessed-contrib');
var screen = blessed.screen();
var line = contrib.line(
{ style: { line: "yellow", text: "green", baseline: "black" } }
);
screen.append(line);
Summary
tui-rs offers a more performant and flexible solution for building terminal user interfaces, leveraging Rust's strengths. It provides greater customization options but requires more setup and Rust knowledge. blessed-contrib, on the other hand, offers a simpler JavaScript-based approach with more pre-built widgets, making it easier for quick prototyping and development. The choice between the two depends on the project requirements, performance needs, and the developer's familiarity with the respective languages and ecosystems.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
blessed-contrib
Build dashboards (or any other application) using ascii/ansi art and javascript.
Friendly to terminals, ssh and developers. Extends blessed with custom drawille and other widgets.
You should also check WOPR: a markup for creating terminal reports, presentations and infographics.
Contributors:
Yaron Naveh (@YaronNaveh) Chris (@xcezzz) Miguel Valadas (@mvaladas) Liran Tal (@lirantal)
Demo (full size):
Running the demo
git clone https://github.com/yaronn/blessed-contrib.git
cd blessed-contrib
npm install
node ./examples/dashboard.js
Works on Linux, OS X and Windows. For Windows follow the pre requisites.
Installation (to build custom projects)
npm install blessed blessed-contrib
Usage
You can use any of the default widgets of blessed (texts, lists and etc) or the widgets added in blessed-contrib (described below). A layout is optional but useful for dashboards. The widgets in blessed-contrib follow the same usage pattern:
var blessed = require('blessed')
, contrib = require('blessed-contrib')
, screen = blessed.screen()
, line = contrib.line(
{ style:
{ line: "yellow"
, text: "green"
, baseline: "black"}
, xLabelPadding: 3
, xPadding: 5
, label: 'Title'})
, data = {
x: ['t1', 't2', 't3', 't4'],
y: [5, 1, 7, 5]
}
screen.append(line) //must append before setting data
line.setData([data])
screen.key(['escape', 'q', 'C-c'], function(ch, key) {
return process.exit(0);
});
screen.render()
See below for a complete list of widgets.
Widgets
Line Chart
var line = contrib.line(
{ style:
{ line: "yellow"
, text: "green"
, baseline: "black"}
, xLabelPadding: 3
, xPadding: 5
, showLegend: true
, wholeNumbersOnly: false //true=do not show fraction in y axis
, label: 'Title'})
var series1 = {
title: 'apples',
x: ['t1', 't2', 't3', 't4'],
y: [5, 1, 7, 5]
}
var series2 = {
title: 'oranges',
x: ['t1', 't2', 't3', 't4'],
y: [2, 1, 4, 8]
}
screen.append(line) //must append before setting data
line.setData([series1, series2])
Examples: simple line chart, multiple lines, 256 colors
Bar Chart
var bar = contrib.bar(
{ label: 'Server Utilization (%)'
, barWidth: 4
, barSpacing: 6
, xOffset: 0
, maxHeight: 9})
screen.append(bar) //must append before setting data
bar.setData(
{ titles: ['bar1', 'bar2']
, data: [5, 10]})
Stacked Bar Chart
bar = contrib.stackedBar(
{ label: 'Server Utilization (%)'
, barWidth: 4
, barSpacing: 6
, xOffset: 0
//, maxValue: 15
, height: "40%"
, width: "50%"
, barBgColor: [ 'red', 'blue', 'green' ]})
screen.append(bar)
bar.setData(
{ barCategory: ['Q1', 'Q2', 'Q3', 'Q4']
, stackedCategory: ['US', 'EU', 'AP']
, data:
[ [ 7, 7, 5]
, [8, 2, 0]
, [0, 0, 0]
, [2, 3, 2] ]
})
Map
var map = contrib.map({label: 'World Map'})
map.addMarker({"lon" : "-79.0000", "lat" : "37.5000", color: "red", char: "X" })
Gauge
var gauge = contrib.gauge({label: 'Progress', stroke: 'green', fill: 'white'})
gauge.setPercent(25)
Stacked Gauge
Either specify each stacked portion with a percent
and stroke
...
var gauge = contrib.gauge({label: 'Stacked '})
gauge.setStack([{percent: 30, stroke: 'green'}, {percent: 30, stroke: 'magenta'}, {percent: 40, stroke: 'cyan'}])
Or, you can just supply an array of numbers and random colors will be chosen.
var gauge = contrib.gauge({label: 'Stacked Progress'})
gauge.setStack([30,30,40])
Donut
var donut = contrib.donut({
label: 'Test',
radius: 8,
arcWidth: 3,
remainColor: 'black',
yPadding: 2,
data: [
{percent: 80, label: 'web1', color: 'green'}
]
});
Data passed in uses percent
and label
to draw the donut graph. Color is optional and defaults to green.
donut.setData([
{percent: 87, label: 'rcp','color': 'green'},
{percent: 43, label: 'rcp','color': 'cyan'},
]);
Updating the donut is as easy as passing in an array to setData
using the same array format as in the constructor. Pass in as many objects to the array of data as you want, they will automatically resize and try to fit. However, please note that you will still be restricted to actual screen space.
You can also hardcode a specific numeric into the donut's core display instead of the percentage by passing an percentAltNumber
property to the data, such as:
var donut = contrib.donut({
label: 'Test',
radius: 8,
arcWidth: 3,
remainColor: 'black',
yPadding: 2,
data: [
{percentAltNumber: 50, percent: 80, label: 'web1', color: 'green'}
]
});
See an example of this in one of the donuts settings on ./examples/donut.js
.
LCD Display
var lcd = contrib.lcd(
{ segmentWidth: 0.06 // how wide are the segments in % so 50% = 0.5
, segmentInterval: 0.11 // spacing between the segments in % so 50% = 0.550% = 0.5
, strokeWidth: 0.11 // spacing between the segments in % so 50% = 0.5
, elements: 4 // how many elements in the display. or how many characters can be displayed.
, display: 321 // what should be displayed before first call to setDisplay
, elementSpacing: 4 // spacing between each element
, elementPadding: 2 // how far away from the edges to put the elements
, color: 'white' // color for the segments
, label: 'Storage Remaining'})
lcd.setDisplay(23 + 'G'); // will display "23G"
lcd.setOptions({}) // adjust options at runtime
Please see the examples/lcd.js for an example. The example provides keybindings to adjust the segmentWidth
and segmentInterval
and strokeWidth
in real-time so that you can see how they manipulate the look and feel.
Rolling Log
var log = contrib.log(
{ fg: "green"
, selectedFg: "green"
, label: 'Server Log'})
log.log("new log line")
Picture
(Also check the new blessed image implementation which has several benefits over this one.)
var pic = contrib.picture(
{ file: './flower.png'
, cols: 25
, onReady: ready})
function ready() {screen.render()}
note: only png images are supported
Sparkline
var spark = contrib.sparkline(
{ label: 'Throughput (bits/sec)'
, tags: true
, style: { fg: 'blue' }})
sparkline.setData(
[ 'Sparkline1', 'Sparkline2'],
[ [10, 20, 30, 20]
, [40, 10, 40, 50]])
Table
var table = contrib.table(
{ keys: true
, fg: 'white'
, selectedFg: 'white'
, selectedBg: 'blue'
, interactive: true
, label: 'Active Processes'
, width: '30%'
, height: '30%'
, border: {type: "line", fg: "cyan"}
, columnSpacing: 10 //in chars
, columnWidth: [16, 12, 12] /*in chars*/ })
//allow control the table with the keyboard
table.focus()
table.setData(
{ headers: ['col1', 'col2', 'col3']
, data:
[ [1, 2, 3]
, [4, 5, 6] ]})
Tree
var tree = contrib.tree({fg: 'green'})
//allow control the table with the keyboard
tree.focus()
tree.on('select',function(node){
if (node.myCustomProperty){
console.log(node.myCustomProperty);
}
console.log(node.name);
}
// you can specify a name property at root level to display root
tree.setData(
{ extended: true
, children:
{
'Fruit':
{ children:
{ 'Banana': {}
, 'Apple': {}
, 'Cherry': {}
, 'Exotics': {
children:
{ 'Mango': {}
, 'Papaya': {}
, 'Kiwi': { name: 'Kiwi (not the bird!)', myCustomProperty: "hairy fruit" }
}}
, 'Pear': {}}}
, 'Vegetables':
{ children:
{ 'Peas': {}
, 'Lettuce': {}
, 'Pepper': {}}}}})
Options
- keys : Key to expand nodes. Default : ['enter','default']
- extended : Should nodes be extended/generated by default? Be careful with this setting when using a callback function. Default : false
- template :
- extend : Suffix "icon" for closed node. Default : '[+]'
- retract : Suffix "icon" for opened node. Default : '[-]'
- lines : Show lines in tree. Default : true
Nodes
Every node is a hash and it can have custom properties that can be used in "select" event callback. However, there are several special keys :
- name
- Type :
string
- Desc : Node name
- If the node isn't the root and you don't specify the name, will be set to hash key
- Example :
{ name: 'Fruit'}
- Type :
- children
- Type :
hash
orfunction(node){ return children }
- Desc : Node children.
- The function must return a hash that could have been used as children property
- If you use a function, the result will be stored in
node.childrenContent
andchildren
- Example :
- Hash :
{'Fruit':{ name: 'Fruit', children:{ 'Banana': {}, 'Cherry': {}}}}
- Function : see
examples/explorer.js
- Hash :
- Type :
- childrenContent
- Type :
hash
- Desc : Children content for internal usage DO NOT MODIFY
- If
node.children
is a hash,node.children===node.childrenContent
- If
node.children
is a function, it's used to store thenode.children()
result - You can read this property, but you should never write it.
- Usually this will be used to check
if(node.childrenContent)
in yournode.children
function to generate children only once
- Type :
- extended
- Type :
boolean
- Desc : Determine if this node is extended
- No effect when the node have no child
- Default value for each node will be
treeInstance.options.extended
if the nodeextended
option is not set - Example :
{'Fruit':{ name: 'Fruit', extended: true, children:{ 'Banana': {}, 'Cherry': {}}}}
- Type :
Markdown
var markdown = contrib.markdown()
markdown.setMarkdown('# Hello \n blessed-contrib renders markdown using `marked-terminal`')
Colors
You can use 256 colors (source):
function randomColor() {
return [Math.random() * 255,Math.random()*255, Math.random()*255]
}
line = contrib.line(
{
...
, style: { line: randomColor(), text: randomColor(), baseline: randomColor() }
})
Layouts
Grid
A grid layout can auto position your elements in a grid layout. When using a grid, you should not create the widgets, rather specify to the grid which widget to create and with which params. Each widget can span multiple rows and columns.
var screen = blessed.screen()
var grid = new contrib.grid({rows: 12, cols: 12, screen: screen})
//grid.set(row, col, rowSpan, colSpan, obj, opts)
var map = grid.set(0, 0, 4, 4, contrib.map, {label: 'World Map'})
var box = grid.set(4, 4, 4, 4, blessed.box, {content: 'My Box'})
screen.render()
Carousel
A carousel layout switches between different views based on time or keyboard activity. One use case is an office dashboard with rotating views:
var blessed = require('blessed')
, contrib = require('./')
, screen = blessed.screen()
function page1(screen) {
var map = contrib.map()
screen.append(map)
}
function page2(screen) {
var line = contrib.line(
{ width: 80
, height: 30
, left: 15
, top: 12
, xPadding: 5
, label: 'Title'
})
var data = [ { title: 'us-east',
x: ['t1', 't2', 't3', 't4'],
y: [0, 0.0695652173913043, 0.11304347826087, 2],
style: {
line: 'red'
}
}
]
screen.append(line)
line.setData(data)
}
screen.key(['escape', 'q', 'C-c'], function(ch, key) {
return process.exit(0);
});
var carousel = new contrib.carousel( [page1, page2]
, { screen: screen
, interval: 3000 //how often to switch views (set 0 to never swicth automatically)
, controlKeys: true //should right and left keyboard arrows control view rotation
})
carousel.start()
Samples
Terminal Dashboard
Running the sample
git clone https://github.com/yaronn/blessed-contrib.git
cd blessed-contrib
npm install
node ./examples/dashboard.js
Installation (for a custom dashboard)
npm install blessed
npm install blessed-contrib
A simple dashboard
var blessed = require('blessed')
, contrib = require('blessed-contrib')
, screen = blessed.screen()
, grid = new contrib.grid({rows: 1, cols: 2, screen: screen})
var line = grid.set(0, 0, 1, 1, contrib.line,
{ style:
{ line: "yellow"
, text: "green"
, baseline: "black"}
, xLabelPadding: 3
, xPadding: 5
, label: 'Stocks'})
var map = grid.set(0, 1, 1, 1, contrib.map, {label: 'Servers Location'})
var lineData = {
x: ['t1', 't2', 't3', 't4'],
y: [5, 1, 7, 5]
}
line.setData([lineData])
screen.key(['escape', 'q', 'C-c'], function(ch, key) {
return process.exit(0);
});
screen.render()
Rich dashboard
See source code
Troubleshooting
If you see questions marks or some (or all) missign characters try running with these env vars to fix encoding / terminal:
$> LANG=en_US.utf8 TERM=xterm-256color node your-code.js
License
This library is under the MIT License
More Information
Top Related Projects
A high-level terminal interface library for node.js.
Minimalist Go package aimed at creating Console User Interfaces.
Golang terminal dashboard
simple terminal UI for git commands
A powerful little TUI framework 🏗
Build terminal user interfaces and dashboards using Rust
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot