or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-inquirer--select

Interactive command line select/list prompt component with customizable theming, pagination, search, and navigation features

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@inquirer/select@4.3.x

To install, run

npx @tessl/cli install tessl/npm-inquirer--select@4.3.0

index.mddocs/

@inquirer/select

@inquirer/select provides an interactive command line selection prompt component that displays a list of choices for single selection. It offers comprehensive customization options including keyboard navigation, search functionality, theming support, pagination, and accessibility features.

Package Information

  • Package Name: @inquirer/select
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install @inquirer/select or npm install @inquirer/prompts

Core Imports

import select, { Separator } from "@inquirer/select";

For using with the full prompts collection:

import { select, Separator } from "@inquirer/prompts";

Basic Usage

import select, { Separator } from "@inquirer/select";

const answer = await select({
  message: "Select a package manager",
  choices: [
    {
      name: "npm",
      value: "npm",
      description: "npm is the most popular package manager",
    },
    {
      name: "yarn", 
      value: "yarn",
      description: "yarn is an awesome package manager",
    },
    new Separator(),
    {
      name: "pnpm",
      value: "pnpm",
      disabled: "(pnpm is not available)",
    },
  ],
});

console.log(answer); // "npm" or "yarn"

Architecture

@inquirer/select is built on top of the Inquirer.js ecosystem using:

  • React-like Hooks: Uses useState, useKeypress, and other hooks from @inquirer/core for state management
  • Prompt System: Built with createPrompt from @inquirer/core providing consistent prompt interface
  • Theming Engine: Flexible theming system with customizable colors, icons, and display modes
  • Pagination: Built-in pagination for handling long choice lists
  • Navigation Engine: Comprehensive keyboard navigation including arrow keys, number selection, and search

Capabilities

Select Prompt

Main prompt function for creating interactive selection interfaces.

/**
 * Creates an interactive selection prompt
 * @param config - Configuration object for the prompt
 * @returns Promise resolving to the selected choice value
 */
function select<Value, ChoicesObject = ReadonlyArray<string | Separator> | ReadonlyArray<Choice<Value> | Separator>>(
  config: SelectConfig<Value, ChoicesObject>
): Promise<Value>;

interface SelectConfig<
  Value,
  ChoicesObject = ReadonlyArray<string | Separator> | ReadonlyArray<Choice<Value> | Separator>
> {
  /** The question message to display */
  message: string;
  /** Array of choices for selection */
  choices: ChoicesObject extends ReadonlyArray<string | Separator>
    ? ChoicesObject
    : ReadonlyArray<Choice<Value> | Separator>;
  /** Number of choices to display per page (default: 7) */
  pageSize?: number;
  /** Whether to loop navigation at start/end (default: true) */
  loop?: boolean;
  /** Default selected value */
  default?: unknown;
  /** Custom instruction text */
  instructions?: {
    navigation: string;
    pager: string;
  };
  /** Theme customization options */
  theme?: PartialDeep<Theme<SelectTheme>>;
}

Usage Examples:

// Simple string choices
const color = await select({
  message: "Pick a color",
  choices: ["red", "green", "blue"],
});

// Complex choices with metadata
const framework = await select({
  message: "Choose a framework",
  choices: [
    {
      name: "React",
      value: "react",
      description: "A JavaScript library for building user interfaces",
      short: "React",
    },
    {
      name: "Vue.js",
      value: "vue",
      description: "The Progressive JavaScript Framework",
      short: "Vue",
    },
    {
      name: "Angular",
      value: "angular",
      disabled: "Not available in this project",
    },
  ],
  default: "react",
  pageSize: 5,
  loop: false,
});

// With custom theming
const option = await select({
  message: "Select option",
  choices: ["Option A", "Option B", "Option C"],
  theme: {
    helpMode: "always",
    indexMode: "number",
    style: {
      description: (text: string) => `πŸ“ ${text}`,
    },
  },
});

Choice Separators

Visual separators for grouping choices in the selection list.

/**
 * Creates a visual separator for grouping choices
 * @param separator - Optional custom separator text (default: line)
 */
class Separator {
  constructor(separator?: string);
  
  /** Check if an item is a separator */
  static isSeparator(choice: any): choice is Separator;
  
  /** The separator text/line */
  separator: string;
}

Utility Functions

Internal utility functions used by the prompt system.

/**
 * Checks if a choice item is selectable (not a separator and not disabled)
 * @param item - The choice item to check
 * @returns True if the item can be selected
 */
function isSelectable<Value>(
  item: NormalizedChoice<Value> | Separator
): item is NormalizedChoice<Value>;

/**
 * Normalizes choice configurations into a consistent format
 * @param choices - Array of choice configurations or strings
 * @returns Array of normalized choices and separators
 */
function normalizeChoices<Value>(
  choices: ReadonlyArray<string | Separator> | ReadonlyArray<Choice<Value> | Separator>
): Array<NormalizedChoice<Value> | Separator>;

Usage Examples:

import select, { Separator } from "@inquirer/select";

const tool = await select({
  message: "Choose a development tool",
  choices: [
    // Frontend tools
    { name: "React", value: "react" },
    { name: "Vue.js", value: "vue" },
    
    new Separator("--- Backend ---"),
    
    // Backend tools  
    { name: "Node.js", value: "node" },
    { name: "Python", value: "python" },
    
    new Separator(), // Default separator line
    
    // Other
    { name: "Database", value: "db" },
  ],
});

Types

Status Types

/** Prompt status indicating current state */
type Status = 'idle' | 'done' | 'loading';

Choice Configuration

interface Choice<Value> {
  /** The value returned when this choice is selected */
  value: Value;
  /** Display name (defaults to string representation of value) */
  name?: string;
  /** Additional description shown below the choice list when selected */
  description?: string;
  /** Short name displayed after selection (defaults to name) */
  short?: string;
  /** Whether choice is disabled, or custom disabled message */
  disabled?: boolean | string;
  /** Reserved property for type discrimination */
  type?: never;
}

/** Internal normalized choice type used by the prompt system */
interface NormalizedChoice<Value> {
  /** The value returned when this choice is selected */
  value: Value;
  /** Display name (always defined after normalization) */
  name: string;
  /** Additional description shown below the choice list when selected */
  description?: string;
  /** Short name displayed after selection */
  short: string;
  /** Whether choice is disabled, or custom disabled message */
  disabled: boolean | string;
}

Theme Configuration

interface SelectTheme {
  /** Icon configuration */
  icon: {
    /** Cursor icon for selected item */
    cursor: string;
  };
  /** Style functions for different text elements */
  style: {
    /** Style function for disabled choices */
    disabled: (text: string) => string;
    /** Style function for choice descriptions */
    description: (text: string) => string;
  };
  /** When to show help tips */
  helpMode: "always" | "never" | "auto";
  /** Whether to show choice indices */
  indexMode: "hidden" | "number";
}

Dependency Types

/** Deep partial utility type from @inquirer/type */
type PartialDeep<T> = {
  [P in keyof T]?: PartialDeep<T[P]>;
};

/** Base theme interface from @inquirer/core */
interface Theme<ExtensionTheme = {}> {
  prefix: string | { idle: string; done: string };
  spinner: {
    interval: number;
    frames: string[];
  };
  style: {
    answer: (text: string) => string;
    message: (text: string, status: 'idle' | 'done' | 'loading') => string;
    error: (text: string) => string;
    help: (text: string) => string;
    highlight: (text: string) => string;
  };
} & ExtensionTheme;

Note: The theme parameter accepts PartialDeep<Theme<SelectTheme>> where Theme<SelectTheme> extends the base theme from @inquirer/core with SelectTheme properties. The PartialDeep<T> type is imported from @inquirer/type and allows for deep partial customization of theme properties.

Navigation Features

The select prompt supports multiple navigation methods:

Keyboard Navigation

  • Arrow Keys: Navigate up/down through choices
  • Enter: Select current choice
  • Number Keys: Jump to choice by index (1-9, multi-digit supported)
  • Letter Keys: Search choices by typing (case-insensitive)
  • Backspace: Clear search input

Search Functionality

  • Type any text to search through choice names
  • Search is case-insensitive and matches from the beginning of choice names
  • Search timeout of 700ms clears the search automatically
  • Backspace clears current search input

Pagination

  • Configurable page size (default: 7 choices per page)
  • Automatic pagination for long choice lists
  • Help text indicates when more choices are available
  • Smooth scrolling when navigating beyond visible choices

Loop Navigation

  • Configurable looping (default: enabled)
  • When enabled: navigation wraps from last to first choice and vice versa
  • When disabled: navigation stops at first/last selectable choice

Accessibility Features

  • Keyboard-only navigation: Full functionality without mouse
  • Screen reader support: Proper ARIA labels and semantic structure
  • Visual indicators: Clear cursor positioning and selection states
  • Status feedback: Visual confirmation of selection and completion
  • Disabled choice handling: Proper skipping and visual indication of disabled choices
  • Separator handling: Non-selectable separators properly skipped during navigation

Error Handling

/** Thrown when all choices are disabled */
class ValidationError extends Error {
  constructor(message: string);
}

Common Errors:

  • ValidationError: "[select prompt] No selectable choices. All choices are disabled." - Thrown when all provided choices have disabled: true

Error Prevention:

// Ensure at least one choice is selectable
const choices = [
  { name: "Option A", value: "a", disabled: true },
  { name: "Option B", value: "b" }, // At least one enabled
];

// Validate choices before creating prompt
const selectableChoices = choices.filter(choice => !choice.disabled);
if (selectableChoices.length === 0) {
  throw new Error("No selectable choices provided");
}

Advanced Configuration

Custom Instructions

const answer = await select({
  message: "Choose language",
  choices: ["English", "Spanish", "French"],
  instructions: {
    navigation: "Use ↑↓ arrows",
    pager: "Use ↑↓ to see more options",
  },
});

Advanced Theming

const answer = await select({
  message: "Select priority",
  choices: [
    { name: "High", value: "high", description: "Urgent task" },
    { name: "Medium", value: "medium", description: "Normal task" },
    { name: "Low", value: "low", description: "Can wait" },
  ],
  theme: {
    prefix: { idle: "❓", done: "βœ…" },
    helpMode: "always",
    indexMode: "number",
    icon: { cursor: "πŸ‘‰" },
    style: {
      highlight: (text: string) => `\x1b[36m${text}\x1b[0m`, // Cyan
      description: (text: string) => `\x1b[90m${text}\x1b[0m`, // Gray
      disabled: (text: string) => `\x1b[2m${text}\x1b[0m`, // Dim
    },
  },
});

Performance Optimization

// For large choice lists, optimize with pagination
const answer = await select({
  message: "Select from many options",
  choices: largeChoiceArray, // 100+ items
  pageSize: 10, // Show 10 at a time
  loop: false, // Disable looping for better performance
});