Ink Enhanced Select Input: A Flexible Horizontal & Vertical Select Component for the Terminal featured image

Ink Enhanced Select Input: A Flexible Horizontal & Vertical Select Component for the Terminal

December 22, 2024

When building command-line interfaces (CLIs) with React and Ink, one of the key elements is often a menu or select component. While Ink’s ecosystem provides some great out-of-the-box components like ink-select-input, there’s an outstanding feature that I found lacking: true support for a horizontal orientation. For games and other visually complex terminal applications, a horizontal list of options can save valuable vertical space and create a more natural user experience.

The Need for a Horizontal Select Input

During the development of my text-based RPG, Potion Wars, screen real estate became a primary concern. The game relies heavily on menus and selectors for user input, but vertical lists quickly consume too many lines. By adopting a horizontal layout, I could place menus side-by-side, conserving vertical space and giving the UI more breathing room.

I dug into the existing solutions and discovered an older issue in the ink-select-input repository calling for horizontal orientation support. Another developer, H3RSKO, created a fork called ink-select-input-horizontal, but my testing revealed limitations and a few lingering bugs that made it less than ideal for my needs.

Introducing Ink Enhanced Select Input

To address these issues, I decided to build my own component: ink-enhanced-select-input. This component extends the original idea of ink-select-input but adds native support for an orientation prop. With this prop, you can easily switch between a vertical list (the classic style) and a horizontal layout, opening the door to more creative CLI interfaces.

In addition, I’ve added various features and properties over time, as required by Potion Wars’ evolving mechanics:

  • Orientation Prop: Choose between vertical or horizontal for your layout.
  • Custom Indicators & Items: Easily supply your own components, from fancy glyphs to color-coded labels.
  • Hotkey Support: Assign single-character hotkeys for lightning-fast selection.
  • Disabled Items: Exclude certain options from being selected without removing them entirely.
  • Limit Displayed Items: Show only a subset of choices at a time, useful for large lists.
  • Callbacks for onHighlight & onSelect: Hook into state changes to run custom logic.

By developing this component alongside my game, I was able to battle-test it in a real environment, ensuring that it not only worked as expected, but also felt intuitive and stable.

Component Showcase

Below are a number of gifs that demonstrate the ink-enhanced-select-input in action within the tBlackjack game.

Default Vertical & Horizontal Modes

Custom Indicators

Current State & Roadmap

Ink Enhanced Select Input is now published on NPM and available for anyone to integrate into their Ink-based CLIs. It works well, but I’m not stopping there. Here are a few things I’d love to explore in the future:

  • Scrolling / Pagination Support: For large item sets, provide a built-in way to paginate or scroll through items.
  • Dynamic Item Updates: Make it easier to update the list as users perform actions, without losing state or focus.
  • Search / Filtering Integration: Allow users to quickly find the right option via an integrated search field or type-ahead filtering.
  • Extensive Theming Options: More hooks for styling, colors, and layouts, making it easier to adapt to various branding or thematic styles.
  • Accessibility Enhancements: Consider improvements in how the component communicates its state and controls for users relying on assistive technologies.

Feedback & Contributions Welcome

This project was born from the challenges I encountered and the feedback I received regarding existing solutions. Now that it’s open-source, I’m eager to hear from other developers utilizing Ink!

You can find the repository here on GitHub. Feel free to open issues, suggest enhancements, or submit pull requests!