or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

components.mdhooks.mdindex.mdrendering.md
tile.json

tessl/npm-ink

React for CLI - build interactive command-line interfaces using React components and Flexbox layouts

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/ink@5.2.x

To install, run

npx @tessl/cli install tessl/npm-ink@5.2.0

index.mddocs/

Ink

Ink is a React-like framework for building command-line interfaces that brings the familiar component-based development experience of React to terminal applications. It provides a comprehensive set of UI components powered by Facebook's Yoga layout engine to enable Flexbox-style layouts in the terminal, making it possible to create interactive CLI tools with real-time UI updates, focus management, and sophisticated terminal-based interfaces.

Package Information

  • Package Name: ink
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install ink react

Core Imports

import { render, Box, Text, useInput, useApp } from "ink";

For type imports:

import { 
  render, 
  Box, 
  Text, 
  useInput, 
  useApp,
  type AppProps,
  type StdinProps,
  type StdoutProps,
  type StderrProps
} from "ink";

For CommonJS:

const { render, Box, Text, useInput, useApp } = require("ink");

Basic Usage

import React, { useState } from "react";
import { render, Box, Text, useInput, useApp } from "ink";

function Counter() {
  const [count, setCount] = useState(0);
  const { exit } = useApp();

  useInput((input, key) => {
    if (input === "q") {
      exit();
    }

    if (key.upArrow) {
      setCount(count + 1);
    }

    if (key.downArrow) {
      setCount(count - 1);
    }
  });

  return (
    <Box>
      <Text color="green">Counter: {count}</Text>
      <Text dimColor> (Use ↑/↓ to change, 'q' to quit)</Text>
    </Box>
  );
}

// Render the app
render(<Counter />);

Architecture

Ink is built around several key components:

  • React Reconciler: Custom React renderer for terminal output instead of DOM
  • Yoga Layout Engine: Facebook's Flexbox implementation for terminal layouts
  • Component System: React-like components (Box, Text) with styling props
  • Hook System: React hooks for input handling, focus management, and app lifecycle
  • Virtual DOM: Custom DOM implementation optimized for terminal rendering
  • Event System: Keyboard input parsing and event handling for interactive CLIs

Capabilities

Application Rendering

Core functionality for mounting and rendering React component trees to the terminal with full lifecycle management.

function render(
  node: ReactNode,
  options?: NodeJS.WriteStream | RenderOptions
): Instance;

interface RenderOptions {
  stdout?: NodeJS.WriteStream; // default: process.stdout
  stdin?: NodeJS.ReadStream;   // default: process.stdin
  stderr?: NodeJS.WriteStream; // default: process.stderr
  debug?: boolean;             // default: false
  exitOnCtrlC?: boolean;       // default: true
  patchConsole?: boolean;      // default: true
}

interface Instance {
  rerender: (node: ReactNode) => void;
  unmount: () => void;
  waitUntilExit: () => Promise<void>;
  cleanup: () => void;
  clear: () => void;
}

Application Rendering

Layout Components

Essential components for building terminal layouts using Flexbox-style positioning and styling.

// Primary layout container component
function Box(props: BoxProps & { children?: ReactNode }): JSX.Element;

// Text display component with styling options
function Text(props: TextProps & { children?: ReactNode }): JSX.Element;

interface BoxProps {
  // Flexbox layout properties
  flexDirection?: "row" | "column" | "row-reverse" | "column-reverse";
  flexWrap?: "nowrap" | "wrap" | "wrap-reverse";
  flexGrow?: number;
  flexShrink?: number;
  justifyContent?: "flex-start" | "flex-end" | "center" | "space-between" | "space-around" | "space-evenly";
  alignItems?: "flex-start" | "center" | "flex-end" | "stretch";
  // [Additional layout properties...]
}

interface TextProps {
  color?: string;
  backgroundColor?: string;
  bold?: boolean;
  italic?: boolean;
  underline?: boolean;
  strikethrough?: boolean;
  wrap?: "wrap" | "truncate-end" | "truncate-start" | "truncate-middle";
}

Layout Components

User Input Handling

Comprehensive input handling system for creating interactive CLI applications with keyboard navigation and focus management.

// Handle keyboard input with parsed key information
function useInput(
  inputHandler: (input: string, key: Key) => void,
  options?: { isActive?: boolean }
): void;

// Focus management for component navigation
function useFocus(options?: {
  isActive?: boolean;
  autoFocus?: boolean;
  id?: string;
}): { isFocused: boolean; focus: (id: string) => void };

interface Key {
  upArrow: boolean;
  downArrow: boolean;
  leftArrow: boolean;
  rightArrow: boolean;
  return: boolean;
  escape: boolean;
  ctrl: boolean;
  shift: boolean;
  tab: boolean;
  backspace: boolean;
  delete: boolean;
  meta: boolean;
}

User Input Handling

Common Types

// DOM element reference type for measuring and manipulation
interface DOMElement {
  nodeName: string;
  attributes: Record<string, any>;
  childNodes: DOMNode[];
  yogaNode?: YogaNode;
  parentNode?: DOMElement;
  style: Styles;
}

// Context Props types for hooks (also available as individual exports)
interface AppProps {
  readonly exit: (error?: Error) => void;
}

interface StdinProps {
  readonly stdin: NodeJS.ReadStream;
  readonly setRawMode: (value: boolean) => void;
  readonly isRawModeSupported: boolean;
  readonly internal_exitOnCtrlC: boolean;
  readonly internal_eventEmitter: EventEmitter;
}

interface StdoutProps {
  readonly stdout: NodeJS.WriteStream;
  readonly write: (data: string) => void;
}

interface StderrProps {
  readonly stderr: NodeJS.WriteStream;
  readonly write: (data: string) => void;
}

// Comprehensive styling interface based on Yoga layout
interface Styles {
  // Layout
  position?: "absolute" | "relative";
  display?: "flex" | "none";
  overflow?: "visible" | "hidden";
  
  // Flexbox
  flexDirection?: "row" | "column" | "row-reverse" | "column-reverse";
  flexWrap?: "nowrap" | "wrap" | "wrap-reverse";
  flexGrow?: number;
  flexShrink?: number;
  flexBasis?: number | string;
  justifyContent?: "flex-start" | "flex-end" | "center" | "space-between" | "space-around" | "space-evenly";
  alignItems?: "flex-start" | "center" | "flex-end" | "stretch";
  alignSelf?: "flex-start" | "center" | "flex-end" | "auto";
  
  // Dimensions
  width?: number | string;
  height?: number | string;
  minWidth?: number | string;
  minHeight?: number | string;
  
  // Spacing
  margin?: number;
  marginX?: number;
  marginY?: number;
  marginTop?: number;
  marginBottom?: number;
  marginLeft?: number;
  marginRight?: number;
  padding?: number;
  paddingX?: number;
  paddingY?: number;
  paddingTop?: number;
  paddingBottom?: number;
  paddingLeft?: number;
  paddingRight?: number;
  gap?: number;
  columnGap?: number;
  rowGap?: number;
  
  // Borders
  borderStyle?: string;
  borderTop?: boolean;
  borderBottom?: boolean;
  borderLeft?: boolean;
  borderRight?: boolean;
  borderColor?: string;
  borderTopColor?: string;
  borderBottomColor?: string;
  borderLeftColor?: string;
  borderRightColor?: string;
  
  // Text
  textWrap?: "wrap" | "truncate-end" | "truncate-start" | "truncate-middle" | "end" | "middle";
}