You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP โ†’
Socket
Book a DemoInstallSign in
Socket

clack-tree-select

Package Overview
Dependencies
Maintainers
0
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

clack-tree-select

Beautiful, interactive tree selection prompts for Clack CLI apps

1.0.1
latest
Source
npmnpm
Version published
Weekly downloads
441
Maintainers
0
Weekly downloads
ย 
Created
Source

๐ŸŒณ clack-tree-select

npm version npm downloads license

๐Ÿ’– Sponsored by

Stringer CLI

"Make your React & Vue apps multilingual in minutes!"

Stringer CLI Logo
Learn more about Stringer CLI โ†’

Beautiful, interactive tree selection prompts for command-line applications. Built on top of Clack for the best CLI experience.

๐ŸŽฌ Demo

Tree Select Demo

โ–ถ๏ธ Watch Demo on Asciinema

See navigation, hierarchical selection, and smart keyboard shortcuts in action.

โœจ Features

  • ๐ŸŒณ Hierarchical Selection - Select parent directories to select all children
  • โŒจ๏ธ Smart Keyboard Shortcuts - Intuitive navigation with toggle expand/select all
  • ๐ŸŽจ Customizable Styling - Beautiful icons and colors that match your brand
  • ๐Ÿš€ Performance Optimized - Efficient rendering for large directory trees
  • ๐Ÿ“ฑ TypeScript Ready - Full type safety with excellent IntelliSense
  • ๐Ÿ”ง File System Integration - Built-in support for browsing local directories
  • โœ… Validation Support - Custom validation with helpful error messages

๐Ÿ“ฆ Installation

npm install clack-tree-select
yarn add clack-tree-select
pnpm add clack-tree-select

๐Ÿš€ Quick Start

Add tree selection to your existing Clack CLI:

import { treeSelect } from 'clack-tree-select';
import { intro, outro, text, isCancel } from '@clack/prompts';

async function main() {
  intro('๐Ÿš€ Project Setup');

  // Your existing Clack prompts
  const projectName = await text({
    message: 'Project name?',
    placeholder: 'my-project'
  });

  if (isCancel(projectName)) return;

  // Add tree selection seamlessly
  const files = await treeSelect({
    message: 'Select files to process:',
    tree: [
      {
        value: 'src',
        name: 'src',
        children: [
          { value: 'src/components', name: 'components' },
          { value: 'src/pages', name: 'pages' },
          { value: 'src/utils', name: 'utils' }
        ]
      },
      { value: 'package.json', name: 'package.json' }
    ]
  });

  if (isCancel(files)) return;

  outro(`โœ… ${projectName}: Selected ${files.length} files`);
}

main();

Perfect integration - works alongside all your existing Clack prompts! ๐ŸŽฏ

๐ŸŒฒ Beyond Files: Any Tree Data Structure

While clack-tree-select works great with file systems, it's designed as a generic tree selection tool. You can create hierarchical selection prompts for any data structure! Here are some powerful examples:

๐ŸŽจ UI Component Library Selection

const components = await treeSelect({
  message: 'Select UI components to include:',
  tree: [
    {
      value: 'forms',
      name: 'Form Components',
      children: [
        { value: 'forms/input', name: 'Text Input' },
        { value: 'forms/select', name: 'Select Dropdown' },
        { value: 'forms/checkbox', name: 'Checkbox' },
        { value: 'forms/radio', name: 'Radio Button' }
      ]
    },
    {
      value: 'navigation',
      name: 'Navigation',
      children: [
        { value: 'nav/header', name: 'Header' },
        { value: 'nav/sidebar', name: 'Sidebar' },
        { value: 'nav/breadcrumb', name: 'Breadcrumb' },
        { value: 'nav/pagination', name: 'Pagination' }
      ]
    },
    {
      value: 'feedback',
      name: 'Feedback',
      children: [
        { value: 'feedback/alert', name: 'Alert' },
        { value: 'feedback/toast', name: 'Toast' },
        { value: 'feedback/modal', name: 'Modal' },
        { value: 'feedback/tooltip', name: 'Tooltip' }
      ]
    }
  ]
});

๐Ÿข Organization/Department Structure

interface Department {
  id: string;
  name: string;
  manager?: string;
}

const departments = await treeSelect<Department>({
  message: 'Select departments for the training program:',
  tree: [
    {
      value: { id: 'eng', name: 'Engineering', manager: 'Alice' },
      name: 'Engineering',
      children: [
        { value: { id: 'frontend', name: 'Frontend' }, name: 'Frontend Team' },
        { value: { id: 'backend', name: 'Backend' }, name: 'Backend Team' },
        { value: { id: 'devops', name: 'DevOps' }, name: 'DevOps Team' }
      ]
    },
    {
      value: { id: 'product', name: 'Product', manager: 'Bob' },
      name: 'Product',
      children: [
        { value: { id: 'design', name: 'Design' }, name: 'Design Team' },
        { value: { id: 'pm', name: 'Product Management' }, name: 'Product Managers' },
        { value: { id: 'research', name: 'User Research' }, name: 'Research Team' }
      ]
    }
  ]
});

๐Ÿ›๏ธ E-commerce Category Selection

const categories = await treeSelect({
  message: 'Select product categories to feature:',
  tree: [
    {
      value: 'electronics',
      name: 'Electronics',
      children: [
        {
          value: 'computers',
          name: 'Computers',
          children: [
            { value: 'laptops', name: 'Laptops' },
            { value: 'desktops', name: 'Desktops' },
            { value: 'tablets', name: 'Tablets' }
          ]
        },
        {
          value: 'phones',
          name: 'Mobile Phones',
          children: [
            { value: 'smartphones', name: 'Smartphones' },
            { value: 'accessories', name: 'Phone Accessories' }
          ]
        }
      ]
    },
    {
      value: 'clothing',
      name: 'Clothing',
      children: [
        { value: 'mens', name: "Men's Clothing" },
        { value: 'womens', name: "Women's Clothing" },
        { value: 'kids', name: "Kids' Clothing" }
      ]
    }
  ]
});

๐Ÿ“‹ Feature/Permission Selection

interface Permission {
  id: string;
  scope: string;
  level: 'read' | 'write' | 'admin';
}

const permissions = await treeSelect<Permission>({
  message: 'Select permissions for this role:',
  tree: [
    {
      value: { id: 'users', scope: 'users', level: 'admin' },
      name: 'User Management',
      children: [
        { 
          value: { id: 'users-read', scope: 'users', level: 'read' }, 
          name: 'View Users' 
        },
        { 
          value: { id: 'users-write', scope: 'users', level: 'write' }, 
          name: 'Edit Users' 
        },
        { 
          value: { id: 'users-admin', scope: 'users', level: 'admin' }, 
          name: 'Manage Users' 
        }
      ]
    },
    {
      value: { id: 'content', scope: 'content', level: 'admin' },
      name: 'Content Management',
      children: [
        { 
          value: { id: 'content-read', scope: 'content', level: 'read' }, 
          name: 'View Content' 
        },
        { 
          value: { id: 'content-write', scope: 'content', level: 'write' }, 
          name: 'Edit Content' 
        }
      ]
    }
  ]
});

๐ŸŽฏ Key Benefits for Non-File Data

  • Type Safety: Full TypeScript support with custom data types
  • Flexible Values: Use strings, objects, numbers, or any data type as values
  • Custom Display: name property controls what users see, value is what you get back
  • Rich Hierarchies: Create deep, meaningful organizational structures
  • Batch Selection: Select entire categories and all children automatically

The generic TreeItem<T> interface makes it perfect for any hierarchical data structure in your applications!

๐Ÿ“š API Reference

treeSelect(options)

Creates an interactive tree selection prompt.

Options

OptionTypeDefaultDescription
messagestringrequiredThe prompt message to display
treeTreeItem[]requiredThe tree structure to display
multiplebooleantrueAllow multiple selections
initialValuesT[][]Pre-selected values
requiredbooleanfalseRequire at least one selection
maxItemsnumberundefinedMaximum visible items (scrolling)
iconsIconOptionsdefault iconsCustom icons for tree items
showHelpbooleantrueShow keyboard shortcuts in validation

TreeItem Interface

interface TreeItem<T = any> {
  value: T;              // Unique identifier
  name?: string;         // Display name (falls back to value)
  open?: boolean;        // Initially expanded
  children?: TreeItem<T>[] | string[] | T[];  // Child items
}

Icon Options

interface IconOptions {
  directory?: string;    // Default: '๐Ÿ“'
  file?: string;         // Default: '๐Ÿ“„'  
  expanded?: string;     // Default: 'โ–ผ'
  collapsed?: string;    // Default: 'โ–ถ'
}

fileSystemTreeSelect(options)

Creates a tree selection prompt from a file system directory.

const files = await fileSystemTreeSelect({
  message: 'Select files from your project:',
  root: './src',
  includeFiles: true,
  includeHidden: false,
  maxDepth: 3,
  filter: (path) => !path.includes('node_modules')
});

โŒจ๏ธ Keyboard Shortcuts

ShortcutAction
โ†‘ / โ†“Navigate up/down
โ† / โ†’Collapse/expand directory
SpaceToggle selection
Ctrl+EToggle expand/collapse all
Ctrl+AToggle select/deselect all
EnterSubmit selection
Ctrl+CCancel prompt

๐ŸŽฏ Advanced Examples

Custom Icons and Styling

const result = await treeSelect({
  message: 'Choose components to generate:',
  tree: components,
  icons: {
    directory: '๐Ÿ“‚',
    file: 'โš›๏ธ',
    expanded: '๐Ÿ“‚', 
    collapsed: '๐Ÿ“'
  },
  multiple: true,
  required: true
});

Single Selection Mode

const configFile = await treeSelect({
  message: 'Choose a configuration file:',
  tree: [
    {
      value: 'config',
      name: 'config',
      open: true,
      children: [
        { value: 'tsconfig.json', name: 'TypeScript Config' },
        { value: 'package.json', name: 'Package Config' },
        { value: 'vite.config.js', name: 'Vite Config' }
      ]
    }
  ],
  multiple: false,
  required: true
});

Note: In single selection mode, only leaf nodes (files without children) can be selected. Parent directories are shown but not selectable, ensuring users select actual items rather than containers.

File System Integration

import { fileSystemTreeSelect } from 'clack-tree-select';

const selectedFiles = await fileSystemTreeSelect({
  message: 'Select files to process:',
  root: process.cwd(),
  includeFiles: true,
  includeHidden: false,
  maxDepth: 3,
  filter: (path) => {
    // Exclude common non-source directories
    return !path.includes('node_modules') && 
           !path.includes('.git') && 
           !path.includes('dist');
  }
});

Custom Validation

const result = await treeSelect({
  message: 'Select at least 2 components:',
  tree: componentTree,
  validate: (selected) => {
    if (!selected || selected.length < 2) {
      return 'Please select at least 2 components to continue.';
    }
  }
});

๐Ÿ”ง Integration Examples

With Package Managers

// Ask user to select packages to install
const packages = await treeSelect({
  message: 'Select packages to install:',
  tree: [
    {
      value: 'react',
      name: 'React',
      children: [
        { value: 'react-dom', name: 'React DOM' },
        { value: 'react-router', name: 'React Router' }
      ]
    },
    {
      value: 'build-tools',
      name: 'Build Tools',
      children: [
        { value: 'vite', name: 'Vite' },
        { value: 'typescript', name: 'TypeScript' }
      ]
    }
  ]
});

With Monorepos

// Select packages in a monorepo
const workspaces = await fileSystemTreeSelect({
  message: 'Select workspaces to build:',
  root: './packages',
  includeFiles: false,  // Only directories
  maxDepth: 1,
  filter: (path) => {
    // Only include directories with package.json
    return fs.existsSync(`${path}/package.json`);
  }
});

๐ŸŽจ Theming

The tree select automatically adapts to your terminal's color scheme and follows Clack's beautiful styling conventions:

  • Selected items: Green checkboxes (โ—ผ)
  • Unselected items: Gray checkboxes (โ—ป)
  • Active item: Cyan highlighting
  • Directories: Folder icons with expand/collapse indicators
  • Files: Document icons

๐Ÿ”— Integration with Existing Clack CLIs

This package is designed as a drop-in addition to your existing Clack CLI. No changes needed to your current setup!

// Your existing CLI
import { intro, text, select, multiselect, outro } from '@clack/prompts';
// Just add this import โ†“
import { treeSelect } from 'clack-tree-select';

async function myCLI() {
  intro('My Existing CLI');
  
  const name = await text({ message: 'Project name?' });
  const framework = await select({ /* ... */ });
  
  // New: Add tree selection anywhere in your flow
  const files = await treeSelect({
    message: 'Select files to process:',
    tree: myFileTree
  });
  
  const tools = await multiselect({ /* ... */ });
  outro('Done!');
}

Zero breaking changes - just add treeSelect where you need hierarchical selection!

๐Ÿงช Examples

Check out the examples/ directory for interactive demos:

cd examples
pnpm install

# Basic tree-select functionality
pnpm tree-select

# Complete integration with other Clack prompts
pnpm integration

The integration demo shows a real CLI workflow mixing treeSelect with text, select, multiselect, and confirm prompts.

๐Ÿค Contributing

We welcome contributions! Please see our Contributing Guide for details.

  • Fork the repository
  • Create your feature branch (git checkout -b feature/amazing-feature)
  • Commit your changes (git commit -m 'Add some amazing feature')
  • Push to the branch (git push origin feature/amazing-feature)
  • Open a Pull Request

๐Ÿ“ License

This project is licensed under the MIT License - see the LICENSE file for details.

Made with โค๏ธ for the CLI community

GitHub โ€ข NPM โ€ข Issues

Keywords

cli

FAQs

Package last updated on 04 Aug 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

About

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.

  • Terms
  • Privacy
  • Security

Made with โšก๏ธ by Socket Inc

U.S. Patent No. 12,346,443 & 12,314,394. Other pending.