or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

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

0

# @inquirer/select

1

2

@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.

3

4

## Package Information

5

6

- **Package Name**: @inquirer/select

7

- **Package Type**: npm

8

- **Language**: TypeScript

9

- **Installation**: `npm install @inquirer/select` or `npm install @inquirer/prompts`

10

11

## Core Imports

12

13

```typescript

14

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

15

```

16

17

For using with the full prompts collection:

18

19

```typescript

20

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

21

```

22

23

## Basic Usage

24

25

```typescript

26

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

27

28

const answer = await select({

29

message: "Select a package manager",

30

choices: [

31

{

32

name: "npm",

33

value: "npm",

34

description: "npm is the most popular package manager",

35

},

36

{

37

name: "yarn",

38

value: "yarn",

39

description: "yarn is an awesome package manager",

40

},

41

new Separator(),

42

{

43

name: "pnpm",

44

value: "pnpm",

45

disabled: "(pnpm is not available)",

46

},

47

],

48

});

49

50

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

51

```

52

53

## Architecture

54

55

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

56

57

- **React-like Hooks**: Uses useState, useKeypress, and other hooks from @inquirer/core for state management

58

- **Prompt System**: Built with createPrompt from @inquirer/core providing consistent prompt interface

59

- **Theming Engine**: Flexible theming system with customizable colors, icons, and display modes

60

- **Pagination**: Built-in pagination for handling long choice lists

61

- **Navigation Engine**: Comprehensive keyboard navigation including arrow keys, number selection, and search

62

63

## Capabilities

64

65

### Select Prompt

66

67

Main prompt function for creating interactive selection interfaces.

68

69

```typescript { .api }

70

/**

71

* Creates an interactive selection prompt

72

* @param config - Configuration object for the prompt

73

* @returns Promise resolving to the selected choice value

74

*/

75

function select<Value, ChoicesObject = ReadonlyArray<string | Separator> | ReadonlyArray<Choice<Value> | Separator>>(

76

config: SelectConfig<Value, ChoicesObject>

77

): Promise<Value>;

78

79

interface SelectConfig<

80

Value,

81

ChoicesObject = ReadonlyArray<string | Separator> | ReadonlyArray<Choice<Value> | Separator>

82

> {

83

/** The question message to display */

84

message: string;

85

/** Array of choices for selection */

86

choices: ChoicesObject extends ReadonlyArray<string | Separator>

87

? ChoicesObject

88

: ReadonlyArray<Choice<Value> | Separator>;

89

/** Number of choices to display per page (default: 7) */

90

pageSize?: number;

91

/** Whether to loop navigation at start/end (default: true) */

92

loop?: boolean;

93

/** Default selected value */

94

default?: unknown;

95

/** Custom instruction text */

96

instructions?: {

97

navigation: string;

98

pager: string;

99

};

100

/** Theme customization options */

101

theme?: PartialDeep<Theme<SelectTheme>>;

102

}

103

```

104

105

**Usage Examples:**

106

107

```typescript

108

// Simple string choices

109

const color = await select({

110

message: "Pick a color",

111

choices: ["red", "green", "blue"],

112

});

113

114

// Complex choices with metadata

115

const framework = await select({

116

message: "Choose a framework",

117

choices: [

118

{

119

name: "React",

120

value: "react",

121

description: "A JavaScript library for building user interfaces",

122

short: "React",

123

},

124

{

125

name: "Vue.js",

126

value: "vue",

127

description: "The Progressive JavaScript Framework",

128

short: "Vue",

129

},

130

{

131

name: "Angular",

132

value: "angular",

133

disabled: "Not available in this project",

134

},

135

],

136

default: "react",

137

pageSize: 5,

138

loop: false,

139

});

140

141

// With custom theming

142

const option = await select({

143

message: "Select option",

144

choices: ["Option A", "Option B", "Option C"],

145

theme: {

146

helpMode: "always",

147

indexMode: "number",

148

style: {

149

description: (text: string) => `πŸ“ ${text}`,

150

},

151

},

152

});

153

```

154

155

### Choice Separators

156

157

Visual separators for grouping choices in the selection list.

158

159

```typescript { .api }

160

/**

161

* Creates a visual separator for grouping choices

162

* @param separator - Optional custom separator text (default: line)

163

*/

164

class Separator {

165

constructor(separator?: string);

166

167

/** Check if an item is a separator */

168

static isSeparator(choice: any): choice is Separator;

169

170

/** The separator text/line */

171

separator: string;

172

}

173

```

174

175

### Utility Functions

176

177

Internal utility functions used by the prompt system.

178

179

```typescript { .api }

180

/**

181

* Checks if a choice item is selectable (not a separator and not disabled)

182

* @param item - The choice item to check

183

* @returns True if the item can be selected

184

*/

185

function isSelectable<Value>(

186

item: NormalizedChoice<Value> | Separator

187

): item is NormalizedChoice<Value>;

188

189

/**

190

* Normalizes choice configurations into a consistent format

191

* @param choices - Array of choice configurations or strings

192

* @returns Array of normalized choices and separators

193

*/

194

function normalizeChoices<Value>(

195

choices: ReadonlyArray<string | Separator> | ReadonlyArray<Choice<Value> | Separator>

196

): Array<NormalizedChoice<Value> | Separator>;

197

```

198

199

**Usage Examples:**

200

201

```typescript

202

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

203

204

const tool = await select({

205

message: "Choose a development tool",

206

choices: [

207

// Frontend tools

208

{ name: "React", value: "react" },

209

{ name: "Vue.js", value: "vue" },

210

211

new Separator("--- Backend ---"),

212

213

// Backend tools

214

{ name: "Node.js", value: "node" },

215

{ name: "Python", value: "python" },

216

217

new Separator(), // Default separator line

218

219

// Other

220

{ name: "Database", value: "db" },

221

],

222

});

223

```

224

225

## Types

226

227

### Status Types

228

229

```typescript { .api }

230

/** Prompt status indicating current state */

231

type Status = 'idle' | 'done' | 'loading';

232

```

233

234

### Choice Configuration

235

236

```typescript { .api }

237

interface Choice<Value> {

238

/** The value returned when this choice is selected */

239

value: Value;

240

/** Display name (defaults to string representation of value) */

241

name?: string;

242

/** Additional description shown below the choice list when selected */

243

description?: string;

244

/** Short name displayed after selection (defaults to name) */

245

short?: string;

246

/** Whether choice is disabled, or custom disabled message */

247

disabled?: boolean | string;

248

/** Reserved property for type discrimination */

249

type?: never;

250

}

251

252

/** Internal normalized choice type used by the prompt system */

253

interface NormalizedChoice<Value> {

254

/** The value returned when this choice is selected */

255

value: Value;

256

/** Display name (always defined after normalization) */

257

name: string;

258

/** Additional description shown below the choice list when selected */

259

description?: string;

260

/** Short name displayed after selection */

261

short: string;

262

/** Whether choice is disabled, or custom disabled message */

263

disabled: boolean | string;

264

}

265

```

266

267

### Theme Configuration

268

269

```typescript { .api }

270

interface SelectTheme {

271

/** Icon configuration */

272

icon: {

273

/** Cursor icon for selected item */

274

cursor: string;

275

};

276

/** Style functions for different text elements */

277

style: {

278

/** Style function for disabled choices */

279

disabled: (text: string) => string;

280

/** Style function for choice descriptions */

281

description: (text: string) => string;

282

};

283

/** When to show help tips */

284

helpMode: "always" | "never" | "auto";

285

/** Whether to show choice indices */

286

indexMode: "hidden" | "number";

287

}

288

```

289

290

### Dependency Types

291

292

```typescript { .api }

293

/** Deep partial utility type from @inquirer/type */

294

type PartialDeep<T> = {

295

[P in keyof T]?: PartialDeep<T[P]>;

296

};

297

298

/** Base theme interface from @inquirer/core */

299

interface Theme<ExtensionTheme = {}> {

300

prefix: string | { idle: string; done: string };

301

spinner: {

302

interval: number;

303

frames: string[];

304

};

305

style: {

306

answer: (text: string) => string;

307

message: (text: string, status: 'idle' | 'done' | 'loading') => string;

308

error: (text: string) => string;

309

help: (text: string) => string;

310

highlight: (text: string) => string;

311

};

312

} & ExtensionTheme;

313

```

314

315

**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.

316

317

## Navigation Features

318

319

The select prompt supports multiple navigation methods:

320

321

### Keyboard Navigation

322

- **Arrow Keys**: Navigate up/down through choices

323

- **Enter**: Select current choice

324

- **Number Keys**: Jump to choice by index (1-9, multi-digit supported)

325

- **Letter Keys**: Search choices by typing (case-insensitive)

326

- **Backspace**: Clear search input

327

328

### Search Functionality

329

- Type any text to search through choice names

330

- Search is case-insensitive and matches from the beginning of choice names

331

- Search timeout of 700ms clears the search automatically

332

- Backspace clears current search input

333

334

### Pagination

335

- Configurable page size (default: 7 choices per page)

336

- Automatic pagination for long choice lists

337

- Help text indicates when more choices are available

338

- Smooth scrolling when navigating beyond visible choices

339

340

### Loop Navigation

341

- Configurable looping (default: enabled)

342

- When enabled: navigation wraps from last to first choice and vice versa

343

- When disabled: navigation stops at first/last selectable choice

344

345

## Accessibility Features

346

347

- **Keyboard-only navigation**: Full functionality without mouse

348

- **Screen reader support**: Proper ARIA labels and semantic structure

349

- **Visual indicators**: Clear cursor positioning and selection states

350

- **Status feedback**: Visual confirmation of selection and completion

351

- **Disabled choice handling**: Proper skipping and visual indication of disabled choices

352

- **Separator handling**: Non-selectable separators properly skipped during navigation

353

354

## Error Handling

355

356

```typescript { .api }

357

/** Thrown when all choices are disabled */

358

class ValidationError extends Error {

359

constructor(message: string);

360

}

361

```

362

363

**Common Errors:**

364

365

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

366

367

**Error Prevention:**

368

369

```typescript

370

// Ensure at least one choice is selectable

371

const choices = [

372

{ name: "Option A", value: "a", disabled: true },

373

{ name: "Option B", value: "b" }, // At least one enabled

374

];

375

376

// Validate choices before creating prompt

377

const selectableChoices = choices.filter(choice => !choice.disabled);

378

if (selectableChoices.length === 0) {

379

throw new Error("No selectable choices provided");

380

}

381

```

382

383

## Advanced Configuration

384

385

### Custom Instructions

386

387

```typescript

388

const answer = await select({

389

message: "Choose language",

390

choices: ["English", "Spanish", "French"],

391

instructions: {

392

navigation: "Use ↑↓ arrows",

393

pager: "Use ↑↓ to see more options",

394

},

395

});

396

```

397

398

### Advanced Theming

399

400

```typescript

401

const answer = await select({

402

message: "Select priority",

403

choices: [

404

{ name: "High", value: "high", description: "Urgent task" },

405

{ name: "Medium", value: "medium", description: "Normal task" },

406

{ name: "Low", value: "low", description: "Can wait" },

407

],

408

theme: {

409

prefix: { idle: "❓", done: "βœ…" },

410

helpMode: "always",

411

indexMode: "number",

412

icon: { cursor: "πŸ‘‰" },

413

style: {

414

highlight: (text: string) => `\x1b[36m${text}\x1b[0m`, // Cyan

415

description: (text: string) => `\x1b[90m${text}\x1b[0m`, // Gray

416

disabled: (text: string) => `\x1b[2m${text}\x1b[0m`, // Dim

417

},

418

},

419

});

420

```

421

422

### Performance Optimization

423

424

```typescript

425

// For large choice lists, optimize with pagination

426

const answer = await select({

427

message: "Select from many options",

428

choices: largeChoiceArray, // 100+ items

429

pageSize: 10, // Show 10 at a time

430

loop: false, // Disable looping for better performance

431

});

432

```