How to use Inquirer.js

Inquirer is a promise-based npm package used in Node projects to create CLI (Command Line Interface) tools for query-based tasks

Mat Wilmot
JavaScript in Plain English

--

In this article I want to talk about a CLI tool that I really enjoy using, and hopefully someone learns something along the way.

Let’s start at the beginning: What is Inquirer?

Inquirer is a promise-based npm package used in Node projects to create CLI (Command Line Interface) tools for query-based tasks. It’s great for asking the user questions, validating user inputs, and doing stuff with the responses given.

I have used Inquirer, alongside a mysql database, to create a CLI tool called the ‘employee manager’. It asks the user what they would like to do, and gives them a list of options. They can add new staff, assign roles, departments, and offices, set salaries, and so much more — all without having to create a front-end.

What’s Node?

Node.js is a JavaScript runtime built on Chrome’s V8 JavaScript engine. For more information on what Node is and how to set it up, click here. You’ll need Node before you can use Inquirer.

So how do I use Inquirer?

Glad you asked! For the sake of this article, we’re going to build up a simple Inquirer-based project, starting at the very beginning and working all the way to so more in-depth stuff. Their documentation (link at the bottom) has all the info you’ll need to get set up, but let’s cover it here too.

If you haven’t done so already, initialize npm in your project by typing the following into your terminal at the root directory of your project:

npm init -y

Now you’re ready to install Inquirer. Type the following into your terminal:

npm install inquirer

The next step involves bringing the Inquirer library into the file you’re working on. You can do that by adding the following line to the start of your code:

const inquirer = require("inquirer")

So now that we’ve brought inquirer into our project, let’s build our first inquiry and run it. Every inquiry starts with the same code:

inquirer.prompt()

So we access the inquirer library and use the prompt method to display our question to the user. But it’s more complicated than that — inquirer takes an array of objects for its questions. So we open an array inside the parentheses, and then an object inside of that array, to give us something like this:

inquirer.prompt([{}])

Each question object should consist of at least three keys:

  • name - how you refer to the question (and the answer given) later on
  • type - what type of question is this? (input, multiple choice, numerical etc)
  • message - the question you’re asking the user

Using this new knowledge, we can create a basic question that looks something like this:

inquirer
.prompt([
{
name: "user_name",
type: "input",
message: "What is your name?",
},
]);

It’s important to note that the default option for ‘type’ is ‘input’ and therefore isn’t actually necessary in this scenario, but I like to include it for the sake of clarity.

But we’re not done yet, we’ve asked the question but we’re not doing anything with the answer. The answer is given back to us as an object where the key is the ‘name’ property of the question, and the answer is its value. You can access the answer using .then() with a callback function inside. Let’s say we want to print the answer to this question to the console, we could use the following code:

inquirer
.prompt([
{
name: "user_name",
type: "input",
message: "What is your name?",
},
])
.then((answer) => {
console.log("Hello " + answer.user_name);
});

Congratulations, you just wrote your first inquiry using Inquirer.js. To run this question, type the following into your console:

node <filename>

For the purpose of this article, I wrote my own file to demonstrate.

A screenshot of some Inquirer code and it’s output in the terminal
Demonstrating usage and expected outcome

Let’s take it a step further

So we’ve asked a question, how do we ask multiple questions? It’s as easy as adding another question object to the array. In the following example, I have added on to the code we wrote earlier, with a few small modifications, to ask the user for their first and last names:

inquirer
.prompt([
{
name: "first_name",
type: "input",
message: "What is your first name?",
},
{
name: "last_name",
type: "input",
message: "What is your last name?",
},
])
.then((answer) => {
console.log("Hello", answer.first_name, answer.last_name);
});

Types of questions

So we’ve learned to add input-based questions. What if we want the user to select from a range of possible options? All we need to do is change the ‘type’ field of the question. Inquirer offers many types for your questions, the most common ones I use are:

  • Input
  • Number
  • Confirm
  • List
  • Checkbox
  • Password

We’ve already seen some input type questions, so let’s see what we can do with the other types.

type: number

The following is an example of a question that uses a number and prints the result to the console.

inquirer
.prompt([
{
name: "pet_count",
type: "number",
message: "How many pets do you own?",
},
])
.then((answer) => {
console.log("You own", answer.pet_count, "pets");
});

It comes with some built-in validation that returns ‘NaN’ if you try to enter something that isn’t a number (e.g. “eight”). We can use this to our advantage and build in a conditional that asks the question again if you didn’t give a number by making the question into a function like so:

const getPetCount = () => {
inquirer
.prompt([
{
name: "pet_count",
type: "number",
message: "How many pets do you own?",
},
])
.then((answer) => {
if (!answer.pet_count) {
console.log("That wasn't a number!");
getPetCount();
} else {
console.log("You own", answer.pet_count, "pets");
});
};
getPetCount();

What we did was turn the question into a re-usable function, and call the question again if the answer comes back as false. Note that, since the question function is not immediately invoked, we need to actually call the function below where we declared it.

type: confirm

Confirm gives the user a simple yes or no option and returns a boolean value as the answer. The following code is an example of how to use the confirm type:

inquirer
.prompt([
{
name: "wants_pizza",
type: "confirm",
message: "Do you want a free pizza?",
},
])
.then((answer) => {
console.log(answer.wants_pizza);
});

The user is presented with the question:

Do you want a free pizza? (Y/n)

A simple Y or N will give you ‘true’ or ‘false’. You could use this to build up a series of questions, all saved as functions, to make a pizza order builder. You do want a pizza? How many pizzas do you want? What address should we deliver the pizzas to? That’s a series of questions using confirm, number, and input question types. But what crust should the pizza have?

type: list

The list type requires you to add an additional key to your question object: a choices array. This will present the user with a list of options to pick from and save their submission as the answer to the question. This type completely prevents the user from entering their own inputs and restricts their choices to your pre-defined list. Here’s an example:

inquirer
.prompt([
{
name: "pizza_crust",
type: "list",
message: "Choose your crust:",
choices: ["Thin Crust", "Stuffed Crust", "Pan"],
},
])
.then((answer) => {
console.log(answer.pizza_crust);
});

The user will be able to pick their crust type from the list and their choice will be printed to the console. If we stick with the pizza order builder idea, let’s say you defined an ‘order’ object at the start of the document, with keys for an address, a crust, number of pizzas, etc.. you could be pushing the values from these answers to that object, then move on to the next question. So what if we want to select multiple options from a list — pizza toppings, for example?

type: checkbox

Checkbox works similarly to a list, in that you have to provide a choices array, except the user can select multiple options. This would be a great way to select pizza toppings. Here’s an example:

const toppingArray = ["Cheese", "Pepperoni", "Onions", "Peppers", "Jalapeños", "Chicken"]inquirer
.prompt([
{
name: "pizza_toppings",
type: "checkbox",
message: "Choose your toppings:",
choices: toppingArray,
},
])
.then((answer) => {
console.log(answer.pizza_toppings);
});

The user will be given the question “Choose your toppings:” and then be presented with a list of options, which, in this example, I defined previously in a variable. The user can use space to select/deselect options, and press enter to submit their answer. Once answered, the answers are saved as strings in an array. An answer to this question might look like this:

["Cheese", "Onions", "Peppers", "Chicken"]

Interesting idea, you can save these answers to a variable and use them again later in another ‘list’ or ‘checkbox’ style question.

type: password

This example doesn’t really fit in to the pizza order builder example, but it’s an important one to cover. The password type will hide the user input completely. No asterisks or blanked out characters, you will see absolutely nothing as you type. This is incredibly useful, though, as anyone looking over your shoulder can’t even see how long your password is! Here’s an example:

inquirer
.prompt([
{
name: "user_password",
type: "password",
message: "Enter Password:",
},
])
.then((answer) => {
console.log(answer.user_password);
});

Obviously, you don’t want to print the sensitive information you just typed directly into the console, but doing this initially is a great way to test that it worked. A better solution in a finished product may be to save the password to a variable or immediately submit it along with a username to log someone into a service.

Want to build a pizza order builder?

That’s awesome. I’ve created a super simple example and uploaded it to GitHub, feel free to clone the repo and see how everything works!

So what else can inquirer do?

One of my favorite features in Inquirer, from before I learned I could separate all my questions into functions, is ‘when’. In a more complex scenario than the pizza order builder, you might want to add a follow-up question that only gets asked if the user selected a certain answer from a previous question. Here’s an example of how to use ‘when’:

inquirer
.prompt([
{
name: "wants_pizza",
type: "confirm",
message: "Do you want a free pizza?",
},
{
name: "confirm_answer",
type: "confirm",
message: "Are you sure?",
when: (answers) => answers.wants_pizza === false,
},
])
.then((answers) => {
if (answers.wants_pizza) {
console.log("The user wants free pizza");
} else if (answers.confirm_answer) {
// the user definitely doesn't want pizza
} else {
// the user changed their mind
// run the function to ask this question again
}
});

So we can see that the ‘when’ property is actually using a callback function with a basic conditional. If the answer was false, then ask if the user is sure. In the .then() block, we use a conditional to see:

  • If the first question was answered as ‘true’, do something.
  • If the first answer was not true, if the second answer was true, the user definitely doesn’t want pizza, run some kind of exit function here
  • else the user said they didn’t want pizza, then changed their mind, so they should be redirected to the initial question

It’s important to note that if the user says they do want a free pizza, they don’t get asked if they are sure — this is the power of ‘when’. By using ‘when’, we can ask a question only when a given criteria is met, and skip it otherwise.

So should I split my inquiries up into functions, or use ‘when’?

In my opinion, both have their use cases. Splitting things up into functions is great for making reusable questions, but the answers to those questions are confined to the scope of their .then() blocks unless you save them to a variable outside of that scope. In the case of the pizza order builder, this was fine since each question contributed a value to an object.

The pizza order builder could just as easily have been two functions — one to display the start menu, and one that contains every follow-up question after that, since we always ask every question in that list.

One argument for using the ‘when’ feature is that it can save on the number of lines of code written and make your files a little shorter; you don’t need to write a whole inquirer.prompt() block, and then have a conditional to either send you to that question, or to the next question. Another benefit is that by asking questions in this way, you don’t lose the answer to the question that took you to that point by changing scope.

Default Values

Inquirer allows you to add default values to your inquiries, to speed up navigation and make suggestions to the user. Here’s an example of how it might be used:

const mediaArray = ["Facebook", "Wikipedia", "Medium"];inquirer
.prompt([
{
name: "fav_media",
type: "list",
message: "What is your favorite source for info?",
choices: mediaArray,
default: "Medium",
},
])
.then((answer) => {
console.log(answer.fav_media);
});

Now, when the user is asked for their favorite source of info, the selected option will be the third option — “Medium”.

example of what functionality the default option gives us
How the inquiry begins when you use a ‘default’ option

This can be very useful if you’re trying to implement CRUD functionality into your project, specifically the Update part. You can pull the existing value into a variable or function argument, and use that as the default value.

More Information

  • If you want to learn more in-depth features in Inquirer.js, you can view the official docs on npm here.

Credit where it’s due

  • Thank you to Squirrel for their article on how to add code blocks to Medium articles. This thing looked a mess before I found that article.
  • Thank you to Thomas W. Smith for teaching me all of this (and so much more) in the first place, and for proof-reading this article.

--

--