Requirements

You should check for these binaries to be installed on your system before continuing. Here is a sample output of an example to help you test these out.

$ node --version
v10.16.0
$ npm --version
6.9.0
$ i3 --version
i3 version 4.17 (2019-08-03) © 2009 Michael Stapelberg and contributors

Usage

Create a directory

$ mkdir my-i3bar

Go into that directory

$ cd my-i3bar

Initialize a new NPM project

$ npm init --yes

Install the "@i3bar/core" package

$ npm install --save-dev @i3bar/core

Create the main script

$ touch main.js

Open the main script with your favorite editor (here, VIM)

$ vim main.js

Import the "@i3bar/core" utilities

"use strict";

const { I3bar, I3Block } = require("@i3bar/core");

Create a new bar instance

const bar = new I3bar();

Create a new block

const block = new I3Block({ full_text: "Hello, i3!" });

Add the block to the bar

bar.addBlock(block);

Add a refresh time to the bar

bar.setSecondsBetweenRefreshes(5);

Start the bar

bar.start();

Open the i3 configuration file

$ vim ~/.config/i3/config

Update the bar command

bar {
    status_command node /path/to/my-i3bar/main.js
}

Reload the bar

$ i3 reload

API

Create a new bar

const { I3Bar } = require("@i3bar/core");

const bar = new I3Bar();

Enable events

const { I3Bar } = require("@i3bar/core");

const bar = new I3Bar();

bar.enableEvents();

This is required for listening to the bar events.

Listen to bar events

const { I3Bar, I3Block } = require("@i3bar/core");

const bar = new I3Bar();
const block = new I3Block({ full_text: "volume", name: "volume" });

bar.addBlock(block);
bar.enableEvents();

bar.on("leftClick", function(blockName, modifiers) {
  if (blockName === "volume") {
    //...
  } else if (blockName === "brightness" && modifiers.includes("Shift")) {
    //...
  }
});

bar.on("rightClick", function(blockName, modifiers) {
  //...
});

bar.on("middleClick", function(blockName, modifiers) {
  //...
});

bar.on("mouseWheelDown", function(blockName, modifiers) {
  //...
});

bar.on("mouseWheelUp", function(blockName, modifiers) {
  //...
});

blockName is a string containing the "name" of the block where the event occured, while modifiers is an array containing the modifiers attached to the event like "Shift" or "Control"

Set the refresh time between each updates of the bar

const { I3Bar } = require("@i3bar/core");

const bar = new I3Bar();

bar.setSecondsBetweenRefreshes(5);

If you need to refresh the bar often, try not to set this value too low as this will increase your CPU usage. Instead, use events and timers in Node.js (see FAQ).

Add a block to the bar

const { I3Bar, I3Block } = require("@i3bar/core");

const bar = new I3Bar();
const block = new I3Block({ full_text: "" });

bar.addBlock(block);

Manually trigger an update of the bar

const { I3Bar} = require("@i3bar/core");

const bar = new I3Bar();

bar.render();

Start the bar

const { I3Bar } = require("@i3bar/core");

const bar = new I3Bar();

bar.start();

Create a block

const { I3Block } = require("@i3bar/core");

const block = new I3Block({ full_text: "" });

Add a block with a dynamic text

const { I3Block } = require("@i3bar/core");

function getText() {
  return "";
}

async function getTextAsync() {
  return "";
}

function getTextPromise() {
  return new Promise(function(resolve) {
    resolve("");
  });
}

const block1 = new I3Block({ full_text: getText });
const block2 = new I3Block({ full_text: getTextAsync });
const block3 = new I3Block({ full_text: getTextPromise });

Update the block manually

const { I3Block } = require("@i3bar/core");

const block = new I3Block({ full_text: "loading..." });

block.update("full_text", "loaded");

FAQ

How to add dynamic values for the "full_text" property?

Using a function

function getTime() {
  const date = new Date();

  return `${date.getHours().toString().padStart(2. "0")}:${date.getMinutes().toString().padStart(2, "0")}`;
}

const block = new I3Block({ full_text: getTime });

Using an asynchronous function

const { promisify } = require("util");
const { exec } = require("child_process"); 
const execute = promisify(exec);

async function getBattery(command) {
  try {
    const battery = await execute("cat /sys/class/power_supply/BAT0/capacity");

    return battery.stdout.trim() + "%";
  } catch {
    return "??%";
  }
}
            
const block = new I3Block({ full_text: getBattery });
            

Using the built-in update() method

Note that this is the prefered method as it does not block the main thread.

const { exec } = require("child_process");

const block = new I3Block({ full_text: "" });

exec("xbacklight -get", function(exception, output, error) {
  if (!exception && !error) {
    block.update("full_text", `${output.trim()}%`); 
    bar.render();
  }
});

Using setInterval() to update on a different interval than the bar

const { get } = require("https");

const block = new I3Block({ full_text: "" });
const TEN_MINUTES = 1000 * 60 * 10;

function updateWeather() {
  get("https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b6907d289e10d714a6e88b30761fae22", function(response) {
    response.on("data", function() {
      const weather = JSON.parse(data);

      block.update("full_text", `${weather.main.temp}°F`);
    });
  });
}

updateWeather();
setInterval(updateWeather, TEN_MINUTES);

How to update the bar on events?

const { exec } = require("child_process");
const { promisify } = require("util");

const execute = promisify(exec);

async function getBrightness() {
  try {
    const brightness = await execute("xbacklight -get");

    return `${Math.floor(brightness.stdout)}%`;
  } catch {
    return "??%";
  }
}

const block = new I3Block({ full_text: getBrightness, name: "brightness" });

bar.on("leftClick", async function(blockName) {
  if (blockName === "brightness") {
    try {
      await execute("xbacklight -set $(( $(xbacklight -get) + 1 ))");
      bar.render();
    } catch {}
  }
});

bar.enableEvents();

Events available are: "leftClick", "rightClick", "middleClick", "mouseWheelUp" & "mouseWheelDown"

How to use modifiers with events?

bar.on("leftClick", async function(blockName, modifiers) {
  if (blockName === "brightness" && modifiers.includes("Shift")) {
    //...
  }
});