/ blessed

Create Blessed custom widgets

As I mention in a previous post, the principle behind building a Blessed application is on appending widgets to the screen, so you may roll really quick into re-writing the same functionality or creating wired wrappers to always based on the same widgets that the Blessed API provide us.

So, how do we create our own widgets based on the existing ones to create new functionality?

The answer, of course is with inheritance.

Creating a basic widget

There are two fundaments on creating a widget with Blessed:

  • Every widget inherits from Element with a distinct type (string) attribute.
  • Since Element inherits from Node, then everything is a Node.

Translating this statements into code would result in something like this:

var Blessed = require('blessed');

var NewWidget = function (options) {
  if (!(this instanceof Blessed.Node)) {
    return new NewWidget(options);
  }

  options = options || {};
  Blessed.Element.call(this, options);
};

NewWidget.prototype = Object.create(Blessed.Element.prototype);
NewWidget.prototype.type = 'modal';

At this point you could use NewWidget just like any other widget. So screen.append(NewWidget({ ... })); should work like a basic Box.

Adding functionality

We can add new methods or define custom events to our widgets. This will give us the possibility to create new characteristics to the widgets.

var ChatHistory = function (options) {
  if (!(this instanceof Blessed.Node)) {
    return new ChatHistory(options);
  }

  options = options || {};
  options.shrink = true;
  Blessed.Element.call(this, options);
};

ChatHistory.prototype = Object.create(Blessed.Element.prototype);
ChatHistory.prototype.type = 'chatHistory';

// Define a instance property called `messages` that will store the message list.
ChatHistory.property._messages = [];

/**
 * Add a message to the history.
 * @param {String} msg
 */
ChatHistory.prototype.addMessage = function (msg) {
  var self = this;

  // Store the message into the widget list.
  this._messages.push(msg);

  // Set the widget content.
  this.setContent(this._messages.join('\n'));
};

Now, the addMessage method is available for any ChatHistory instance and we can call addMessage('This is my message.'); to display a message on the chat history.
So, If we want to display something like this:

chat-history-showcase-1

We, will write the following code:

// Create a new `ChatHistory` instance.
var chat = ChatHistory({
  height: '100%',
  padding: 1,
  tags: true,
  width: '100%'
});

// Display dummy messages.
chat.addMessage('People assume that time is a strict progression of cause to effect,');
chat.addMessage('but {underline}actually{/underline} from a non-linear, non-subjective viewpoint -');
chat.addMessage('it\'s more like a big ball of wibbly wobbly... time-y wimey... stuff.');

// Append the chat to the screen.
screen.append(chat);

// Render the screen.
screen.render();

Going deeper

Going deeper

Handling events

This is something really easy since all the widgets inherits from the EventEmitter. It even have this events built-in:

adopt - received when node is added to a parent.
remove - received when node is removed from it's current parent.
reparent - received when node gains a new parent.
attach - received when node is attached to the screen directly or somewhere in its ancestry.
detach - received when node is detached from the screen directly or somewhere in its ancestry.

So you can call this.on('attach', function () { ... }); from the widget constructor if you'd like. This is something that blessed-contrib does a lot.

Overriding the render method

Overriding the render method, seems like a something that will break the way that Blessed render the widget.
Lucky for us, the render methods comes with a _render to act as a super, in that way we can override the method, and call the private unmodified version of the render inherited from Element.

ChatHistory.prototype.render = function () {
  // Set the widget content.
  this.setContent(this._messages.join('\n'));

  // Call the super.
  return this._render();
};

This technique is used in a lot of widgets from the Blessed core.


I upload the full example code in this gist. Remember to ⭐️!


Last thing, if you'd like complex visualisations, you should take a look at drawille-canvas-blessed-contrib.