Back to skills
SKILL.md
Clack Guidelines
ASecurityComprehensive guide for building beautiful interactive command-line interfaces using Clack. Use when creating CLI tools with text input, selections, autocomplete, progress tracking, and streaming output.
- 57 stars
- 0 votes
- 0 copies
- 3 views
- Added October 17, 2026
Works with
Security analysis
96/100- Installs packages at runtime which could introduce malicious dependencies
npx -y skills add diegosouzapw/awesome-omni-skill --skill clack-guidelines --agent claude-codeAre you the author of Clack Guidelines?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/diegosouzapw-clack-guidelines)---
name: clack-guidelines
description: Comprehensive guide for building beautiful interactive command-line interfaces using Clack. Use when creating CLI tools with text input, selections, autocomplete, progress tracking, and streaming output.
---
# Clack Guidelines
## Overview
This skill provides guidance for building beautiful interactive command-line interfaces using Clack. It covers common patterns for text input, selections, autocomplete, progress tracking, streaming output, and creating complete interactive CLI applications.
## Quick Start
### Installation
```bash
npm install @clack/prompts
```
### Basic Program
```javascript
import { text, isCancel, cancel } from "@clack/prompts";
const projectPath = await text({
message: "Where should we create your project?",
placeholder: "./my-awesome-project",
initialValue: "./sparkling-solid",
validate: (value) => {
if (!value) return "Please enter a path.";
if (value[0] !== ".") return "Please enter a relative path.";
},
});
if (isCancel(projectPath)) {
cancel("Operation cancelled.");
process.exit(0);
}
console.log(`Creating project at: ${projectPath}`);
```
### Complete Interactive CLI
```javascript
import * as p from "@clack/prompts";
import color from "picocolors";
async function createApp() {
console.clear();
p.intro(color.bgCyan(color.black(" create-myapp ")));
const config = await p.group(
{
name: () =>
p.text({
message: "What is your project name?",
placeholder: "my-awesome-app",
validate: (value) => {
if (!value) return "Project name is required";
},
}),
framework: () =>
p.select({
message: "Choose your framework",
options: [
{ value: "react", label: "React", hint: "Popular" },
{ value: "vue", label: "Vue" },
{ value: "svelte", label: "Svelte" },
],
}),
typescript: () =>
p.confirm({
message: "Use TypeScript?",
initialValue: true,
}),
},
{
onCancel: () => {
p.cancel("Setup cancelled");
process.exit(0);
},
},
);
console.log(config);
}
createApp().catch(console.error);
```
## Common Patterns
### Text Input
Single-line text input with validation and placeholders.
```javascript
import { text } from "@clack/prompts";
const name = await text({
message: "Enter your name",
placeholder: "John Doe",
validate: (value) => {
if (!value) return "Name is required";
},
});
```
### Password Input
Secure password input with masking.
```javascript
import { password } from "@clack/prompts";
const userPassword = await password({
message: "Provide a password",
mask: "•",
validate: (value) => {
if (!value) return "Please enter a password.";
if (value.length < 8) return "Password should have at least 8 characters.";
},
});
```
### Autocomplete Single Selection
Type-ahead search with real-time filtering.
```javascript
import { autocomplete } from "@clack/prompts";
const country = await autocomplete({
message: "Select a country",
options: [
{ value: "us", label: "United States", hint: "NA" },
{ value: "ca", label: "Canada", hint: "NA" },
{ value: "uk", label: "United Kingdom", hint: "EU" },
],
placeholder: "Type to search countries...",
maxItems: 8,
initialValue: "us",
});
```
### Autocomplete Multi-Select
Type-ahead search with multi-selection.
```javascript
import { autocompleteMultiselect } from "@clack/prompts";
const frameworks = await autocompleteMultiselect({
message: "Select frameworks (type to filter)",
options: [
{ value: "react", label: "React", hint: "Frontend/UI" },
{ value: "vue", label: "Vue.js", hint: "Frontend/UI" },
{ value: "nextjs", label: "Next.js", hint: "React Framework" },
],
placeholder: "Type to filter...",
maxItems: 8,
initialValues: ["react", "nextjs"],
required: true,
});
```
### Single Selection Menu
Choose one option from a scrollable list.
```javascript
import { select } from "@clack/prompts";
const projectType = await select({
message: "Pick a project type",
initialValue: "ts",
maxItems: 5,
options: [
{ value: "ts", label: "TypeScript" },
{ value: "js", label: "JavaScript" },
{ value: "rust", label: "Rust" },
{ value: "go", label: "Go" },
],
});
```
### Multi-Select Menu
Select multiple options from a list.
```javascript
import { multiselect } from "@clack/prompts";
const tools = await multiselect({
message: "Select additional tools",
initialValues: ["prettier", "eslint"],
required: true,
options: [
{ value: "prettier", label: "Prettier", hint: "recommended" },
{ value: "eslint", label: "ESLint", hint: "recommended" },
{ value: "stylelint", label: "Stylelint" },
],
});
```
### Confirmation Dialog
Binary yes/no choice.
```javascript
import { confirm } from "@clack/prompts";
const shouldInstallDeps = await confirm({
message: "Install dependencies?",
active: "Yes, please",
inactive: "No, skip",
initialValue: false,
});
```
### Progress Bar
Visual progress indicator for long-running operations.
```javascript
import { progress } from "@clack/prompts";
import { setTimeout } from "node:timers/promises";
const downloadProgress = progress({
style: "block",
max: 100,
size: 40,
});
downloadProgress.start("Downloading packages");
for (let i = 0; i < 100; i += 10) {
await setTimeout(500);
downloadProgress.advance(10);
downloadProgress.message(`Downloaded ${i + 10}%`);
}
downloadProgress.stop("Download complete!");
```
### Spinner Loading Indicator
Display progress for long-running operations.
```javascript
import { spinner } from "@clack/prompts";
import { setTimeout } from "node:timers/promises";
const s = spinner();
s.start("Installing packages via pnpm");
await setTimeout(2000);
s.message("Downloading dependencies");
await setTimeout(1500);
s.stop("Installation complete!");
```
### Task Log with Live Output
Display streaming output that clears on success and persists on error.
```javascript
import { taskLog } from "@clack/prompts";
import { spawn } from "node:child_process";
const log = taskLog({
title: "Running npm install",
limit: 10,
retainLog: true,
spacing: 1,
});
const npmInstall = spawn("npm", ["install"]);
npmInstall.stdout.on("data", (data) => {
log.message(data.toString(), { raw: true });
});
npmInstall.on("close", (code) => {
if (code === 0) {
log.success("Installation complete!");
} else {
log.error("Installation failed!", { showLog: true });
}
});
```
### Streaming Output for LLMs
Stream dynamic content from async iterables.
```javascript
import { stream } from "@clack/prompts";
import { setTimeout } from "node:timers/promises";
await stream.step(
(async function* () {
const words = "Building your application with modern tools".split(" ");
for (const word of words) {
yield word;
yield " ";
await setTimeout(100);
}
})(),
);
```
### Grouped Prompts with Sequential Execution
Execute multiple prompts in sequence with shared state.
```javascript
import * as p from "@clack/prompts";
import color from "picocolors";
p.intro(color.bgCyan(color.black(" create-app ")));
const project = await p.group(
{
path: () =>
p.text({
message: "Where should we create your project?",
placeholder: "./sparkling-solid",
validate: (value) => {
if (!value) return "Please enter a path.";
if (value[0] !== ".") return "Please enter a relative path.";
},
}),
type: ({ results }) =>
p.select({
message: `Pick a project type within "${results.path}"`,
initialValue: "ts",
options: [
{ value: "ts", label: "TypeScript" },
{ value: "js", label: "JavaScript" },
{ value: "rust", label: "Rust" },
],
}),
tools: () =>
p.multiselect({
message: "Select additional tools",
options: [
{ value: "prettier", label: "Prettier", hint: "recommended" },
{ value: "eslint", label: "ESLint", hint: "recommended" },
],
}),
install: () =>
p.confirm({
message: "Install dependencies?",
initialValue: true,
}),
},
{
onCancel: () => {
p.cancel("Operation cancelled.");
process.exit(0);
},
},
);
console.log(project.path, project.type, project.tools, project.install);
```
### Task Execution with Spinners
Run multiple tasks with automatic spinner management.
```javascript
import * as p from "@clack/prompts";
import { setTimeout } from "node:timers/promises";
await p.tasks([
{
title: "Installing dependencies",
task: async (message) => {
message("Downloading packages");
await setTimeout(1000);
message("Building native modules");
await setTimeout(500);
return "Installed 127 packages";
},
},
{
title: "Running linter",
task: async () => {
// Run linter
return "No issues found";
},
},
]);
```
### Logging Messages
Display formatted status messages with different severity levels.
```javascript
import { log } from "@clack/prompts";
import color from "picocolors";
log.info("Starting build process...");
log.step("Compiling TypeScript");
log.success("Build completed successfully!");
log.warn("Some dependencies are outdated");
log.error("Failed to connect to database");
// Custom symbol
log.message("Custom message", {
symbol: color.cyan("→"),
});
```
### Intro, Outro, and Notes
Frame your CLI sessions with beautiful headers.
```javascript
import { intro, outro, note } from "@clack/prompts";
import color from "picocolors";
intro(color.bgCyan(color.black(" my-cli-tool v2.0.0 ")));
// ... prompts and operations ...
note("cd my-project\nnpm install\nnpm run dev", "Next steps");
outro(
`Problems? ${color.underline(color.cyan("https://github.com/myorg/myproject/issues"))}`,
);
```
### Custom Key Bindings
Configure alternative key mappings for navigation.
```javascript
import { updateSettings } from "@clack/prompts";
// Enable WASD navigation
updateSettings({
aliases: {
w: "up",
s: "down",
a: "left",
d: "right",
},
});
```
### Non-Interactive Mode Detection
Handle CI environments where prompts aren't supported.
```javascript
import { text, block } from "@clack/prompts";
// In CI environments, prompts automatically use defaults
const name = await text({
message: "Project name?",
defaultValue: "default-project",
});
// block() utility prevents input in non-TTY environments
const unblock = block();
// Perform operations
unblock();
```
### Cancellation and Error Handling
Robust error handling for user cancellations and validation errors.
```javascript
import * as p from "@clack/prompts";
async function setupProject() {
try {
const responses = await p.group({
name: () =>
p.text({
message: "Project name?",
validate: (v) => {
if (!v) return "Required";
},
}),
confirm: ({ results }) =>
p.confirm({
message: `Create "${results.name}"?`,
}),
});
// Check if any step was cancelled
if (p.isCancel(responses.name) || p.isCancel(responses.confirm)) {
p.cancel("Setup cancelled");
return;
}
if (!responses.confirm) {
p.outro("Setup aborted");
return;
}
// Proceed with setup
p.outro("Project created!");
} catch (error) {
p.log.error(`Setup failed: ${error.message}`);
process.exit(1);
}
}
setupProject();
```
## Advanced Features
### Custom Render Function with @clack/core
Build custom prompts with full control over rendering.
```javascript
import { TextPrompt } from "@clack/core";
import color from "picocolors";
const customPrompt = new TextPrompt({
validate: (value) => (value.length < 3 ? "Too short!" : undefined),
render() {
const title = `>>> ${color.bold("Enter your name")}:`;
const input = this.valueWithCursor || color.dim("(empty)");
switch (this.state) {
case "error":
return `${title}\n${color.red(input)}\n${color.red(this.error)}`;
case "submit":
return `${title} ${color.green(this.value)}`;
case "cancel":
return `${title} ${color.strikethrough(this.value)}`;
default:
return `${title}\n${color.cyan(input)}`;
}
},
});
const result = await customPrompt.prompt();
console.log(`Result: ${result}`);
```
### Event-Driven Custom Prompt
Subscribe to prompt events for advanced interactions.
```javascript
import { TextPrompt } from "@clack/core";
const prompt = new TextPrompt({
render() {
return `Input: ${this.valueWithCursor}`;
},
});
// Listen to events
prompt.on("value", (value) => {
console.log(`Current value: ${value}`);
});
prompt.on("submit", () => {
console.log("User submitted the form");
});
prompt.on("cancel", () => {
console.log("User cancelled");
});
const result = await prompt.prompt();
```
### Complete CLI Application Example
Full-featured setup wizard combining multiple prompt types.
```javascript
import { setTimeout } from "node:timers/promises";
import * as p from "@clack/prompts";
import color from "picocolors";
async function createApp() {
console.clear();
p.intro(color.bgCyan(color.black(" create-myapp ")));
const config = await p.group(
{
name: () =>
p.text({
message: "What is your project name?",
placeholder: "my-awesome-app",
validate: (value) => {
if (!value) return "Project name is required";
if (!/^[a-z0-9-]+$/.test(value)) {
return "Use only lowercase letters, numbers, and hyphens";
}
},
}),
framework: () =>
p.select({
message: "Choose your framework",
options: [
{ value: "react", label: "React", hint: "Popular" },
{ value: "vue", label: "Vue" },
{ value: "svelte", label: "Svelte" },
{ value: "solid", label: "Solid" },
],
}),
features: () =>
p.multiselect({
message: "Select features",
required: false,
options: [
{ value: "router", label: "Router" },
{ value: "state", label: "State Management" },
{ value: "testing", label: "Testing Setup" },
{ value: "ci", label: "CI/CD Pipeline" },
],
}),
typescript: () =>
p.confirm({
message: "Use TypeScript?",
initialValue: true,
}),
install: () =>
p.confirm({
message: "Install dependencies now?",
initialValue: true,
}),
},
{
onCancel: () => {
p.cancel("Setup cancelled");
process.exit(0);
},
},
);
// Execute setup tasks
await p.tasks([
{
title: "Creating project structure",
task: async () => {
// Create project files
return `Created ${config.name}`;
},
},
{
title: "Installing dependencies",
task: async (message) => {
message("Resolving packages...");
await setTimeout(1000);
message("Downloading...");
await setTimeout(2000);
return "Installed 42 packages";
},
enabled: config.install,
},
]);
// Display next steps
const nextSteps = [
`cd ${config.name}`,
config.install ? "" : "npm install",
"npm run dev",
]
.filter(Boolean)
.join("\n");
p.note(nextSteps, "Next steps");
p.outro(
`All set! ${color.underline(color.cyan("https://docs.example.com"))}`,
);
}
async function createProjectFiles(config) {
// Implementation...
}
createApp().catch(console.error);
```
## Detailed API Reference
For comprehensive API documentation including all prompt types, configuration options, and advanced features, see the detailed API reference:
**[references/clack-api.md](references/clack-api.md)**
This reference includes:
- Complete prompt type documentation
- Configuration options for each prompt
- Validation and error handling patterns
- Streaming and async patterns
- Custom key bindings and settings
- Integration with @clack/core
- TypeScript support
- And more
## Resources
### references/
This skill includes detailed API documentation:
- **clack-api.md** - Comprehensive API reference for Clack prompts, organized by prompt type with code examples for each feature.
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.