Skip to main content

Styling

Kraken TUI provides comprehensive styling capabilities including color resolution, text decoration, and borders. All styling is resolved in the Native Core for maximum performance.

Color System

Kraken TUI supports three color modes with automatic terminal capability detection and graceful degradation.

Color Formats

text.setForeground("#FF0000");  // Bright red
text.setBackground("#1E1E1E");  // Dark gray
text.setForeground("#F80");     // Short form: #FF8800
Encoding: 0x01RRGGBB (truecolor mode)Support: Modern terminals (iTerm2, Windows Terminal, Alacritty, etc.)

Color Parsing

The Style Module parses colors into a uniform u32 encoding:
// From source: ts/src/style.ts
export function parseColor(value: string | number): number {
  if (typeof value === "number") {
    if (value === 0) return 0;  // Default
    if (value >= 0 && value <= 255) return 0x02000000 | value;  // ANSI index
    return value;  // Already encoded
  }

  const lower = value.toLowerCase().trim();

  if (lower === "default" || lower === "") return 0;

  // Hex color: "#FF0000" → 0x01FF0000
  if (lower.startsWith("#")) {
    const hex = lower.slice(1);
    if (hex.length === 6) {
      const rgb = parseInt(hex, 16);
      if (!isNaN(rgb)) return 0x01000000 | rgb;
    }
    // Short form: "#F80" → "#FF8800"
    if (hex.length === 3) {
      const r = parseInt(hex[0], 16) * 17;
      const g = parseInt(hex[1], 16) * 17;
      const b = parseInt(hex[2], 16) * 17;
      return 0x01000000 | (r << 16) | (g << 8) | b;
    }
  }

  // Named color: "red" → 0x02000001
  if (lower in NAMED_COLORS) {
    return 0x02000000 | NAMED_COLORS[lower];
  }

  return 0;  // Default fallback
}

Graceful Degradation

The Native Core automatically detects terminal capabilities and degrades colors gracefully: Truecolor → 256-color → 16-color → Monochrome
// You write:
text.setForeground("#FF5733");

// Terminal with truecolor: exact #FF5733
// Terminal with 256-color: closest ANSI color (e.g., 203)
// Terminal with 16-color: closest ANSI color (e.g., red)
// Monochrome terminal: default foreground

Text Decoration

Apply text decoration attributes to widgets:

Bold

text.setBold(true);   // Enable bold
text.setBold(false);  // Disable bold
Bold rendering depends on terminal font support. Some terminals render bold as brighter colors instead of heavier weight.

Italic

text.setItalic(true);   // Enable italic
text.setItalic(false);  // Disable italic
Italic support varies by terminal. Not all monospace fonts include italic variants.

Underline

text.setUnderline(true);   // Enable underline
text.setUnderline(false);  // Disable underline

Combining Decorations

const heading = new Text({ content: "Important" });
heading.setForeground("#FF0000");
heading.setBold(true);
heading.setUnderline(true);
// Bold, underlined, red text

Borders

Add borders around container widgets:

Border Styles

box.setBorderStyle("none");
// No border (default)

Border Colors

box.setBorderStyle("single");
box.setBorderColor("#00FF00");  // Green border
Border color is separate from foreground/background. You can have a green border with red text on a black background.

Border with Content

const panel = new Box();
panel.setBorderStyle("rounded");
panel.setBorderColor("cyan");
panel.setPadding(1, 2, 1, 2);  // Inner spacing

const title = new Text({ content: "Panel Title" });
title.setBold(true);

panel.append(title);

// ╭──────────────╮
// │              │
// │  Panel Title │  ← 1 cell padding top/bottom
// │              │     2 cells padding left/right
// ╰──────────────╯

Opacity

Control widget transparency (composited in the render buffer):
widget.setOpacity(1.0);   // Fully opaque (default)
widget.setOpacity(0.5);   // 50% transparent
widget.setOpacity(0.0);   // Fully transparent (invisible)
Opacity affects the widget and all its descendants. Use sparingly as it increases render complexity.

Opacity Animation

Opacity is commonly animated for fade effects:
// Fade in
widget.setOpacity(0.0);
widget.animate({
  property: "opacity",
  target: 1.0,
  duration: 300,
  easing: "easeOut"
});

// Fade out
widget.animate({
  property: "opacity",
  target: 0.0,
  duration: 300,
  easing: "easeIn"
});

Style Resolution

Explicit Styles vs Theme Defaults

Explicit widget styles always win over theme defaults. Themes provide fallback values for properties you don’t set explicitly.
import { Theme } from "kraken-tui";

const theme = Theme.create();
theme.setForeground("white");  // Default foreground
theme.setBackground("black");  // Default background

const box = new Box();
theme.applyTo(box);
// box uses white on black (from theme)

box.setForeground("red");  // Explicit style
// box now uses red on black (explicit wins)
See the Theming section for more details.

Styling Examples

Syntax-Highlighted Code Block

const codeBlock = new Text({
  content: 'function hello() {\n  console.log("Hello");\n}',
  format: "code",
  language: "javascript"
});
codeBlock.setBackground("#1E1E1E");
codeBlock.setPadding(1, 2, 1, 2);

const container = new Box();
container.setBorderStyle("single");
container.setBorderColor("#444");
container.append(codeBlock);

Styled Button

const button = new Box();
button.setBorderStyle("rounded");
button.setBorderColor("blue");
button.setBackground("#1E3A8A");  // Dark blue
button.setPadding(0, 2, 0, 2);

const label = new Text({ content: "Submit" });
label.setForeground("white");
label.setBold(true);

button.append(label);

// ╭──────────╮
// │  Submit  │  ← Blue background, white bold text
// ╰──────────╯

Status Indicator

function createStatus(level: "info" | "warn" | "error") {
  const status = new Text({ content: level.toUpperCase() });
  status.setBold(true);
  
  switch (level) {
    case "info":
      status.setForeground("#00FF00");  // Green
      break;
    case "warn":
      status.setForeground("#FFA500");  // Orange
      break;
    case "error":
      status.setForeground("#FF0000");  // Red
      break;
  }
  
  return status;
}

const info = createStatus("info");    // Green INFO
const warn = createStatus("warn");    // Orange WARN
const error = createStatus("error");  // Red ERROR

Rainbow Text

const rainbow = new Box({ direction: "row" });

const colors = ["red", "#FFA500", "yellow", "green", "blue", "#4B0082", "#8B00FF"];
const letters = "RAINBOW".split("");

letters.forEach((letter, i) => {
  const span = new Text({ content: letter });
  span.setForeground(colors[i]);
  span.setBold(true);
  rainbow.append(span);
});

// RAINBOW  ← Each letter different color

Performance Considerations

Color parsing happens once per property set in TypeScript, then the u32 encoding crosses FFI. Native Core uses the encoding directly — zero parsing overhead during render.
Text decorations (bold, italic, underline) are stored as bit flags in a single u8, making style checks and comparisons extremely fast.
Borders are rendered using Unicode box-drawing characters. Single-cell writes per corner/edge — minimal overhead.
Opacity requires alpha blending during render. Use sparingly for performance-critical paths. Fully opaque (1.0) and fully transparent (0.0) are optimized fast paths.

Style Best Practices

1

Use Named Colors for Compatibility

Named colors work in all terminals. Use hex colors for branding/design fidelity when you control the deployment environment.
// Good for wide compatibility:
text.setForeground("green");

// Good for precise branding:
text.setForeground("#00D084");  // Exact brand green
2

Prefer Theme Defaults Over Per-Widget Styling

Set common styles once in a theme instead of repeating them on every widget.
const theme = Theme.create();
theme.setForeground("white");
theme.setBackground("black");
theme.applyTo(rootWidget);

// All descendants inherit theme defaults
3

Test in Your Target Terminals

Color rendering varies by terminal emulator. Test in the terminals your users will use (especially for hex colors and decorations).
4

Minimize Opacity Usage

Reserve opacity for animations and overlays. Avoid setting non-1.0 opacity on large subtrees.

Next Steps

Theming

Create reusable theme systems

Animation

Animate colors and opacity

Build docs developers (and LLMs) love