Interactive Command-line Prompts with Inquirer.js

joshtronic

Recently I was reviewing a sample project at work for a potential engineering candidate and was completely blown away by the prompt I was presented with from the command-line script.

I was given a list of items to pick from and was able to arrow through them (as well as use j and k) and it was just magnificent. It was a nice touch and I wanted to learn more about it.

After some digging, I found the package that provided all this command-line prompt goodness. The package is named inquirer, a collection of common interactive command-line user interfaces.

The inquirer package provides a handful of prompts out of the box and is highly configurable as well as extensible by way of a plug-in interface. It even supports promises and async/await syntax.

Getting Started

To start adding amazing prompts to your Node.js scripts, you will need to install the inquirer package via your package manager of choice:

# via npm
$ npm install inquirer --save

# via yarn
$ yarn add inquirer

And within your script, be sure to require inquirer:

const inquirer = require('inquirer');

Basic Usage

Without much configuration we can get up and running with a colorful input prompt:

const inquirer = require('inquirer');

inquirer
  .prompt([
    {
      name: 'faveReptile',
      message: 'What is your favorite reptile?',
    },
  ])
  .then(answers => {
    console.info('Answer:', answers.faveReptile);
  });

But what if the user just hits enter? No big deal, we can add a default value for when that happens:

const inquirer = require('inquirer');

inquirer
  .prompt([
    {
      name: 'faveReptile',
      message: 'What is your favorite reptile?',
      default: 'Alligators, of course!',
    },
  ])
  .then(answers => {
    console.info('Answer:', answers.faveReptile);
  });

Multiple Prompts

You may have noticed the .prompt() method accepts an array or objects. That’s because we can string a series of prompt questions together and all of the answers will be available by name as part of the answers variable once all of the prompts have been resolved:

const inquirer = require('inquirer');

inquirer
  .prompt([
    {
      name: 'faveReptile',
      message: 'What is your favorite reptile?',
      default: 'Alligators, of course!',
    },
    {
      name: 'faveColor',
      message: 'What is your favorite color?',
      default: '#008f68',
    },
  ])
  .then(answers => {
    console.info('Answers:', answers);
  });

Different Types of Prompts

As mentioned, inquirer does support more than just prompting a user for text input. For the sake of example, the following types will be showcased by themselves but you very well could chain them together by passing them in the same array.

List

The list type allows you to present the user with a fixed set of options to pick from, instead of a free form input as the input type provides:

const inquirer = require('inquirer');

inquirer
  .prompt([
    {
      type: 'list',
      name: 'reptile',
      message: 'Which is better?',
      choices: ['alligator', 'crocodile'],
    },
  ])
  .then(answers => {
    console.info('Answer:', answers.reptile);
  });

The user can arrow up and down the list of choices as well as use j and k.

Raw List

Similar to list, rawlist displays a list of choices and allows the user to enter the index of their choice (starting at 1):

const inquirer = require('inquirer');

inquirer
  .prompt([
    {
      type: 'rawlist',
      name: 'reptile',
      message: 'Which is better?',
      choices: ['alligator', 'crocodile'],
    },
  ])
  .then(answers => {
    console.info('Answer:', answers.reptile);
  });

Playing with this prompt type, I found it to be a bit buggy. While it does accept navigating via the arrow keys, navigating up and down between the available choices was fine, but the moment you arrowed up past the first item or arrowed down past the last option, resulted in ever increasing index values as well as NaN showing up in the prompt.

Expandable List

The expand type is reminiscent of some command-line applications that simply present you with a list of characters which map to functionality that can be entered. expand prompts will initially present the user with a list of the available character values and give context to them when the key is pressed:

const inquirer = require('inquirer');

inquirer
  .prompt([
    {
      type: 'expand',
      name: 'reptile',
      message: 'Which is better?',
      choices: [
        {
          key: 'a',
          value: 'alligator',
        },
        {
          key: 'c',
          value: 'crocodile',
        },
      ],
    },
  ])
  .then(answers => {
    console.info('Answer:', answers.reptile);
  });

By default the H option is included which stands for “Help” and upon entering H and hitting enter will switch to a list of the options, indexed by their characters that can then be entered to make a selection.

Checkbox

Thus far, we’ve only talked about prompts that allow for a single selection to be made. But what if we want to allow the user to select multiple things? That’s where the checkbox type comes in:

const inquirer = require('inquirer');

inquirer
  .prompt([
    {
      type: 'checkbox',
      name: 'reptiles',
      message: 'Which reptiles do you love?',
      choices: [
        'Alligators', 'Snakes', 'Turtles', 'Lizards',
      ],
    },
  ])
  .then(answers => {
    console.info('Answer:', answers.reptiles);
  });

Similar to the other list types, you can use the arrow keys to navigate. To make a selection, you hit SPACE and can also select all with a or invert your selection with i.

Unlike the other types we’ve discussed, the answer for this prompt type will return an array instead of a string. It will always return an array, even if the user opted to not select any items.

Password

Let’s say you wanted to collect some sensitive information from a user. Sure, you could simply use the input type of prompt, but their input would be available in plain text for all to see! In those situations, use the password prompt and the input from the user will be hidden:

const inquirer = require('inquirer');

inquirer
  .prompt([
    {
      type: 'password',
      name: 'secret',
      message: 'Tell me a secret',
    },
  ])
  .then(answers => {
    // Logging out the secret defeats the purpose though ;)
    console.info('Answer:', answers.secret);
  });

Editor

Sometimes a command-line prompt just isn’t enough to convey a larger bit of input, like say, an essay or the contents of a log file. In those situations, the best bet is to direct the user to a full blown editor where they will have a bit more power:

const inquirer = require('inquirer');

inquirer
  .prompt([
    {
      type: 'editor',
      name: 'story',
      message: 'Tell me a story, a really long one!',
    },
  ])
  .then(answers => {
    console.info('Answer:', answers.story);
  });

inquirer will attempt to open a text editor on the user’s system based on the value of the $EDITOR and $VISUAL environment variables. If neither are present, vim (Linux) and notepad.exe (Windows) will be used instead.

  Tweet It

🕵 Search Results

🔎 Searching...

Sponsored by #native_company# — Learn More
#native_title# #native_desc#
#native_cta#