npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@unblessed/node

v1.0.0-alpha.23

Published

Node.js runtime adapter for @unblessed/core terminal UI library

Downloads

2,030

Readme

@unblessed/node

Node.js runtime adapter for @unblessed/core - Build beautiful terminal UIs with ease.

npm version License: MIT

⚠️ ALPHA SOFTWARE - This package is part of the unblessed alpha release. API may change between alpha versions.

Overview

@unblessed/node brings the power of @unblessed/core terminal UI widgets to Node.js applications. It provides a Node.js runtime adapter that handles all platform-specific operations automatically.

Features:

  • 🚀 Auto-initialization - Runtime sets up automatically on import
  • 📦 Zero configuration - Just import and use
  • 🎨 Rich widget library - 30+ widgets for building TUIs
  • ⌨️ Full keyboard & mouse support - Interactive user interfaces
  • 🎯 TypeScript first - Complete type safety
  • 🔧 Compatible - Works with the original blessed API

Why This Package Exists

@unblessed/node is a convenience wrapper that saves you from runtime initialization boilerplate.

Without this package, you'd need to manually initialize the runtime:

import { setRuntime, Screen, Box } from '@unblessed/core';
import fs from 'fs';
import process from 'process';
import path from 'path';
import { Buffer } from 'buffer';
// ... 15+ more imports

// Manual runtime setup (boilerplate!)
setRuntime({
  fs: { readFileSync: fs.readFileSync, existsSync: fs.existsSync, ... },
  path: { join: path.join, resolve: path.resolve, ... },
  process: { stdin: process.stdin, stdout: process.stdout, ... },
  buffer: { Buffer },
  // ... 50+ more lines
});

const screen = new Screen();

With @unblessed/node:

import { Screen, Box } from "@unblessed/node"; // Auto-initialized!

const screen = new Screen();

Key Benefits:

  • ✅ Zero boilerplate - runtime initialized automatically on import
  • ✅ Correct runtime configuration - we handle all the Node.js API wiring
  • ✅ Type safety - full TypeScript support out of the box
  • ✅ Just works - no configuration needed

This package exists to make your life easier while keeping @unblessed/core pure and platform-agnostic.

Installation

npm install @unblessed/node@alpha
# or
pnpm add @unblessed/node@alpha
# or
yarn add @unblessed/node@alpha

Requirements: Node.js >= 22.0.0

Quick Start

import { Screen, Box } from "@unblessed/node";

// Runtime auto-initializes - no setup needed!

const screen = new Screen({
  smartCSR: true,
  title: "Hello unblessed",
});

const box = new Box({
  parent: screen,
  top: "center",
  left: "center",
  width: "50%",
  height: "50%",
  content:
    "{bold}{cyan-fg}Hello, World!{/cyan-fg}{/bold}\n\nPress {inverse} q {/inverse} to quit.",
  tags: true,
  border: { type: "line" },
  style: {
    fg: "white",
    bg: "black",
    border: { fg: "#f0f0f0" },
  },
});

screen.key(["escape", "q", "C-c"], () => {
  process.exit(0);
});

box.focus();
screen.render();

Available Widgets

Layout Widgets

  • Screen - Root container for the application
  • Box - Basic container with borders and styling
  • Layout - Automatic layout manager (horizontal/vertical)
  • Line - Horizontal or vertical line

Input Widgets

  • Form - Form container
  • Input - Single-line text input
  • Textarea - Multi-line text input
  • Textbox - Editor-style text input
  • Button - Clickable button
  • Checkbox - Toggle checkbox
  • RadioButton - Radio button
  • RadioSet - Group of radio buttons

Display Widgets

  • Text - Static or dynamic text
  • List - Scrollable list of items
  • ListTable - Table with list-style rows
  • Table - Grid-based table
  • Log - Scrolling log widget
  • ProgressBar - Progress indicator
  • Loading - Loading spinner
  • Message - Modal message box
  • Question - Yes/no question dialog
  • Prompt - Input prompt dialog
  • BigText - ASCII art text
  • Image - PNG/GIF image renderer
  • ANSIImage - ANSI art image
  • OverlayImage - Layered image
  • FileManager - File browser
  • Listbar - Navigation bar

Container Widgets

  • ScrollableBox - Box with scrolling
  • ScrollableText - Text with scrolling

Examples

The monorepo examples directory contains complete working examples including hello-world, interactive forms, and dashboards.

Common Patterns

Creating Widgets

Always use parent: to attach widgets to their container:

const container = new Box({
  parent: screen, // Attach to screen
  // ... options
});

const button = new Button({
  parent: container, // Attach to container
  // ... options
});

Event Handling

// Global keyboard shortcuts
screen.key(["escape", "q"], () => {
  process.exit(0);
});

// Widget-specific events
button.on("press", () => {
  console.log("Button clicked!");
});

// Mouse events
box.on("click", (data) => {
  console.log("Clicked at", data.x, data.y);
});

Styling

Use inline tags or style objects:

// Inline tags
const text = new Text({
  parent: screen,
  content: "{bold}{red-fg}Error:{/red-fg}{/bold} Something went wrong",
  tags: true,
});

// Style object
const box = new Box({
  parent: screen,
  style: {
    fg: "white",
    bg: "blue",
    border: { fg: "cyan" },
    hover: { bg: "green" },
    focus: { border: { fg: "yellow" } },
  },
});

Focus Management

// Set initial focus
input.focus();

// Tab navigation
input.key("tab", () => {
  button.focus();
});

button.key("tab", () => {
  list.focus();
});

API Reference

Screen

The root container for your application.

const screen = new Screen({
  smartCSR: true, // Smart cursor save/restore
  fastCSR: true, // Fast CSR for terminals that support it
  title: "My App", // Window title
  cursor: {
    artificial: true, // Artificial cursor
    shape: "block", // Cursor shape
    blink: true, // Blinking cursor
  },
  fullUnicode: true, // Full Unicode support
  dockBorders: true, // Dock borders to edges
  ignoreDockContrast: true,
});

Box

Basic container widget.

const box = new Box({
  parent: screen,
  top: 0, // Position (number or string)
  left: 0,
  width: "50%", // Size (number or string)
  height: 10,
  content: "Hello", // Text content
  tags: true, // Enable inline tags
  border: {
    type: "line", // 'line', 'bg', or custom characters
  },
  style: {
    fg: "white",
    bg: "blue",
    border: { fg: "cyan" },
  },
  padding: {
    left: 2,
    right: 2,
    top: 1,
    bottom: 1,
  },
  scrollable: true, // Enable scrolling
  mouse: true, // Enable mouse events
  keys: true, // Enable keyboard events
  vi: true, // Vi-style navigation
});

For complete widget options, see @unblessed/core types.

Architecture

@unblessed/node is a thin wrapper over @unblessed/core that:

  1. Provides NodeRuntime - Implements the Runtime interface with Node.js APIs
  2. Auto-initializes - Sets up the runtime when you import the package
  3. Re-exports widgets - All @unblessed/core widgets available directly
// Internal structure (simplified)
import { setRuntime } from "@unblessed/core";
import fs from "fs";
import process from "process";
// ... other Node.js modules

const runtime = {
  fs,
  process,
  // ... other Node.js APIs
};

// Initialize @unblessed/core with Node.js runtime
setRuntime(runtime);

// Re-export all widgets
export * from "@unblessed/core";

This means you get:

  • ✅ Full Node.js file system access
  • ✅ Real process I/O (stdin/stdout/stderr)
  • ✅ Child process support (for Terminal widget)
  • ✅ Native TTY detection
  • ✅ All Node.js modules available

Terminal Compatibility

Tested and supported terminals:

macOS:

  • iTerm2 ✅
  • Terminal.app ✅
  • Alacritty ✅
  • Kitty ✅

Linux:

  • gnome-terminal ✅
  • konsole ✅
  • xterm ✅
  • rxvt-unicode ✅

Windows:

  • Windows Terminal ✅
  • ConEmu ✅
  • PowerShell ✅

Multiplexers:

  • tmux ✅
  • screen ✅

Environment Variables

  • TERM - Terminal type (default: auto-detected)
  • COLORTERM - Color support indicator
  • NO_COLOR - Disable colors when set

Troubleshooting

Terminal not rendering correctly?

export TERM=xterm-256color
node your-app.js

Mouse not working?

  • Check if your terminal supports mouse events
  • Ensure mouse: true is set on widgets
  • Some terminals in tmux/screen need additional config

Widgets not showing?

  • Verify parent: screen is used for all top-level widgets
  • Call screen.render() after creating widgets
  • Check widget positioning (top, left, width, height)

Keyboard input not working?

  • Widget must have focus: widget.focus()
  • Enable keyboard: keys: true
  • Use screen.key() for global shortcuts

Migration from blessed

@unblessed/node is designed to be compatible with blessed:

// Old blessed code
const blessed = require("blessed");
const screen = blessed.screen();

// New @unblessed/node code
import { Screen } from "@unblessed/node";
const screen = new Screen();

Or use @unblessed/blessed for 100% backward compatibility:

npm install @unblessed/blessed@alpha

Performance

@unblessed/node is optimized for terminal rendering:

  • Smart CSR - Only updates changed regions
  • Efficient diffing - Minimal escape sequences
  • Buffered writes - Batched terminal output
  • Event coalescing - Reduced re-renders

Tips for best performance:

  1. Use smartCSR: true in screen options
  2. Batch widget updates before render()
  3. Use alwaysScroll: false when possible
  4. Limit expensive operations in render loops

Contributing

See the main unblessed repository for contribution guidelines.

License

MIT © Vinicius De Antoni

Related