I built Inklin because I wanted a better terminal styling experience for Node.js

javascript dev.to

I built Inklin because I wanted a better terminal styling experience for Node.js

When working on CLI tools, I kept running into the same limitations with existing styling libraries.

They were good—but once you start building more complex terminal output, a few problems start to show up:

  • nested styles don’t behave predictably
  • module system support can get messy (ESM vs CommonJS)
  • some libraries feel heavier than they should for simple styling

So I built Inklin.

It’s a small terminal styling utility for Node.js that focuses on predictable behavior, modern module support, and minimal overhead.

What Inklin does

Inklin is not trying to replace everything—it’s focused on a few specific improvements.

  1. Smart style nesting

Most terminal styling libraries reset styles when a nested style ends.

That creates unexpected output when combining styles.

Inklin instead tracks a style stack, so parent styles are restored automatically.

Example idea:

red("Error: " + blue("file not found"))

After blue() ends, the output correctly returns to red() instead of resetting to default.

This makes deeply nested styling more predictable in real CLI output.

  1. ESM + CommonJS support out of the box

One of the most annoying parts of modern Node.js libraries is module compatibility.

Inklin works in both environments without extra setup:

  • ESM (import)
  • CommonJS (require)

No dual package confusion, no build hacks required for basic usage.

  1. Modern terminal features

Inklin includes support for:

  • Truecolor (HEX and RGB)
  • OSC 8 hyperlinks (clickable terminal links)

These are useful for modern CLI tools where terminals are no longer just plain text environments.

  1. Lightweight core (~3KB)

The goal was to keep the core small and predictable.

No large dependency tree, no unnecessary abstractions.

How it works internally

Under the hood, Inklin uses a lazy Proxy-based chaining system.

Instead of eagerly computing styles, it builds them dynamically when accessed.

This allows:

  • flexible chaining APIs
  • minimal runtime overhead
  • consistent output behavior

It also uses a recursive structure to manage style composition, which helps keep nesting behavior consistent.

Example usage

import inklin from "inklin";

console.log(
inklin.red.bold("Error:") + " something went wrong"
);

Or chain-style:

inklin.bold.blue("Hello world").log();

Why I built it

The goal wasn’t to reinvent terminal styling.

It was to explore a simpler, more predictable API for CLI output while avoiding some of the edge-case issues I kept running into in real projects.

Especially around:

  • nested styling behavior
  • module compatibility friction
  • lightweight CLI design

Repo

https://github.com/sapirrior/inklin

Feedback welcome

I’d especially appreciate feedback on:

  • API design (is chaining intuitive enough?)
  • edge cases in nested styling
  • performance considerations for CLI-heavy use cases

Source: dev.to

arrow_back Back to Tutorials