BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News Ink: React for Interactive Command-Line Apps

Ink: React for Interactive Command-Line Apps

Ink, a JavaScript library self-described as "React for Command Line Interfaces", recently released its second major iteration. Ink enables the building of command-line applications by assembling React components. Developers may then leverage their React knowledge, and the React ecosystem.

Ink is a React renderer that turns a React component tree into strings to be rendered on an output terminal. Ink 2.0 thus naturally supports React features such as Hooks or Context. It additionally interfaces easily with important components of the React ecosystem, such as Redux.

The documentation gives the following illustrative example:

import React, {Component} from 'react';
import {render, Color} from 'ink';

class Counter extends Component {
  constructor() {
    super();

    this.state = {
      i: 0
    };
  }

  render() {
    return (
      <Color green>
        {this.state.i} tests passed
      </Color>
    );
  }

  componentDidMount() {
    this.timer = setInterval(() => {
      this.setState({
      i: this.state.i + 1
      });
    }, 100);
  }

  componentWillUnmount() {
    clearInterval(this.timer);
  }
}

render(<Counter/>);

which renders in the terminal as:

Basic Ink Counter Application

Ink 2.0 comes with seven built-in components. Another 10 third-party components are also available for composing terminal applications, and 14 more are being migrated to Ink 2.0. Those reusable components address common terminal user interface layouts and behaviors (text input, progress bar, spinner, confirm input, scroll bar, autocomplete, text animation, image displaying and more). The components also tackle important concerns such as linking, routing, animation, or color.

Ink 2.0 uses Yoga, a cross-platform layout engine which implements Flexbox. As such, each element is a Flexbox container and may use the relevant Flexbox parameters (flexShrink, flexGrow, flexDirection and many more). The Box built-in component may as a result be used to configure layouts. The following component:

import {render, Box, Text, Color} from 'ink';

const Flexbox = () => (
    <Box padding={2} flexDirection="column">
        <Box>
            <Box width={14}>
                <Text bold>Total tests:</Text>
            </Box>

            12
        </Box>

        <Box>
            <Box width={14}>
                <Text bold>Passed:</Text>
            </Box>

            <Color green>10</Color>
        </Box>

        <Box>
            <Box width={14}>
                <Text bold>Failed:</Text>
            </Box>

            <Color red>2</Color>
        </Box>
    </Box>
);

render(<Flexbox/>);

would render as follows:

ink flexbox layout example

Ink components can be tested with ink-testing-library, inspired from react-testing-library, a popular alternative to Jest for testing React components. A counter application may for instance be tested with:

import React from 'react';
import {Text} from 'ink';
import {render} from 'ink-testing-library';

const Counter = ({count}) => <Text>Count: {count}</Text>;

const {lastFrame, rerender} = render(<Counter count={0}/>);
lastFrame() === 'Count: 0'; //=> true

rerender(<Counter count={1}/>);
lastFrame() === 'Count: 1'; //=> true

There is a distinction to be made between terminal and command-line applications. Terminal applications may feature full-screen graphical user interfaces with complex navigational and input abilities.

React-blessed, based on the blessed terminal interface library, enables applications such as the following:

React Blessed demo

Ink caters to simpler command-line application interfaces, with simpler input abilities:

Ink.js is available under the MIT open source license. Contributions are welcome via the GitHub package.

Rate this Article

Adoption
Style

BT