npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

hierarchical-folder-tree

v1.1.5

Published

A virtualized hierarchical folders list component for React with comprehensive icon support

Readme

Hierarchical Folders List

A React component for displaying hierarchical folder structures with virtualization, keyboard navigation, and customizable styling.

Features

  • 🚀 DOM Virtualization: Only renders items visible in the viewport for optimal performance
  • ⌨️ Keyboard Navigation: Full keyboard support (arrows, enter, escape)
  • 🎨 Customizable Styling: Easily style and customize with Emotion
  • 🔧 Flexible API: Render custom item content and icons
  • 🌲 Tree View: Familiar folder tree navigation like in Windows/Mac
  • 📦 Small Bundle Size: Lightweight with minimal dependencies
  • 🎯 Comprehensive Icon Support: Multiple ways to provide icons from external sources

Installation

npm install hierarchical-folders-list
# or
yarn add hierarchical-folders-list

TypeScript Requirements

This package requires TypeScript configuration that includes ES2015+ features. Make sure your tsconfig.json includes:

{
  "compilerOptions": {
    "target": "es2015",
    "lib": ["dom", "dom.iterable", "es2015", "es2016", "es2017"],
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true
  }
}

Note: If you see errors about Set or Iterable, ensure your lib array includes "es2015" or later.

Usage

import React from 'react';
import { FolderList } from 'hierarchical-folders-list';

// Sample data
const folderData = [
  {
    id: 'folder-1',
    name: 'Documents',
    isFolder: true,
    children: [
      {
        id: 'folder-1-1',
        name: 'Work',
        isFolder: true,
        children: [
          { id: 'file-1-1-1', name: 'Report.pdf' },
          { id: 'file-1-1-2', name: 'Presentation.pptx' }
        ]
      },
      { id: 'file-1-1', name: 'Resume.docx' }
    ]
  },
  {
    id: 'folder-2',
    name: 'Pictures',
    isFolder: true,
    children: [
      { id: 'file-2-1', name: 'Vacation.jpg' },
      { id: 'file-2-2', name: 'Family.png' }
    ]
  }
];

const App = () => {
  const handleItemClick = (item) => {
    console.log('Item clicked:', item);
  };

  return (
    <div style={{ height: '400px', width: '300px' }}>
      <FolderList
        data={folderData}
        onItemClick={handleItemClick}
        defaultExpandedIds={['folder-1']}
      />
    </div>
  );
};

export default App;

Icon Support

The component provides multiple flexible ways for consumers to provide icons from external sources:

1. Direct Icon Assignment

const data = [
  {
    id: 'file-1',
    name: 'special-file.txt',
    icon: <CustomIcon /> // Direct React element
  }
];

2. Icon Configuration Object

import { FolderList, createFileExtensionIconResolver } from 'hierarchical-folders-list';

const iconConfig = {
  // Icon map with keys
  iconMap: {
    'js': <JavaScriptIcon />,
    'ts': <TypeScriptIcon />,
    'jsx': <ReactIcon />,
    'css': <CSSIcon />,
    'folder': <FolderIcon />,
  },
  
  // Automatic icon key resolution based on file extension
  getIconKey: createFileExtensionIconResolver({
    'html': 'web',
    'md': 'markdown',
  }),
  
  // Default icons
  defaultFolderIcon: <FolderIcon />,
  defaultFileIcon: <FileIcon />,
};

<FolderList data={data} iconConfig={iconConfig} />

3. Icon Resolver Function

const iconConfig = {
  iconResolver: (item, isExpanded) => {
    const isFolder = Boolean(item.isFolder || item.children?.length);
    
    if (isFolder) {
      return isExpanded ? <FolderOpenIcon /> : <FolderIcon />;
    }
    
    // Custom logic for files
    if (item.name.endsWith('.js')) return <JavaScriptIcon />;
    if (item.name.endsWith('.ts')) return <TypeScriptIcon />;
    
    return <DefaultFileIcon />;
  }
};

4. Explicit Icon Keys

const data = [
  {
    id: 'special-folder',
    name: 'Special Folder',
    isFolder: true,
    iconKey: 'special' // Will look up in iconConfig.iconMap['special']
  }
];

5. Legacy renderItemIcon Function

<FolderList
  data={data}
  renderItemIcon={(item, isExpanded) => {
    // Custom icon logic
    return <CustomIcon />;
  }}
/>

Icon Resolution Priority

The component resolves icons in the following order:

  1. Direct icon on item (item.icon)
  2. Legacy renderItemIcon function
  3. Icon from iconMap using item.iconKey
  4. Icon from iconMap using getIconKey() result
  5. Icon from iconResolver function
  6. Default icons from config
  7. Built-in default icons

Keyboard Navigation

The component supports the following keyboard shortcuts:

  • Up/Down Arrows: Navigate between items
  • Right Arrow: Expand folder or navigate to first child
  • Left Arrow: Collapse folder or navigate to parent
  • Enter: Toggle folder expansion
  • Escape: Collapse folder or navigate to parent

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | data | FolderItemData[] | Required | Array of folder/file items to display | | onItemClick | (item: FolderItemData) => void | - | Callback when an item is clicked | | onItemDoubleClick | (item: FolderItemData) => void | - | Callback when an item is double-clicked | | onItemContextMenu | (item: FolderItemData, event: React.MouseEvent) => void | - | Callback for context menu events | | renderItemContent | (item: FolderItemData, isExpanded: boolean) => React.ReactNode | - | Custom renderer for item content | | renderItemIcon | (item: FolderItemData, isExpanded: boolean) => React.ReactNode | - | Custom renderer for item icons (legacy) | | iconConfig | IconConfig | - | Icon configuration object | | itemHeight | number | 28 | Height of each item in pixels | | className | string | - | Additional CSS class for the container | | style | React.CSSProperties | - | Additional inline styles for the container | | defaultExpandedIds | string[] | [] | IDs of items that should be expanded by default | | keyboard | Object | See below | Keyboard navigation options | | virtualizationOptions | Object | See below | Virtualization options |

Keyboard Options

{
  enabled: true,             // Enable keyboard navigation
  expandOnEnter: true,       // Expand folders with Enter key
  collapseOnEscape: true,    // Collapse folders with Escape key
  navigateWithArrows: true   // Navigate with arrow keys
}

Virtualization Options

{
  enabled: true,             // Enable virtualization
  overscan: 10               // Number of items to render outside viewport
}

Types

interface FolderItemData {
  id: string;
  name: string;
  children?: FolderItemData[];
  isFolder?: boolean;
  icon?: React.ReactNode;
  iconKey?: string;
  customData?: any;
}

interface IconConfig {
  iconMap?: Record<string, React.ReactNode>;
  iconResolver?: (item: FolderItemData, isExpanded: boolean) => React.ReactNode | null;
  defaultFolderIcon?: React.ReactNode;
  defaultFileIcon?: React.ReactNode;
  getIconKey?: (item: FolderItemData) => string | null;
}

Utilities

The package exports several utility functions to help with icon management:

import { 
  createFileExtensionIconResolver,
  getFileExtension,
  resolveIcon 
} from 'hierarchical-folders-list';

// Create an icon key resolver based on file extensions
const getIconKey = createFileExtensionIconResolver({
  'html': 'web',
  'md': 'markdown',
});

// Get file extension from filename
const extension = getFileExtension('file.tsx'); // 'tsx'

// Manually resolve icon (used internally)
const icon = resolveIcon(item, isExpanded, iconConfig);

Example

To run the example locally:

  1. Clone this repository
  2. Build the package: npm run build
  3. Serve the example: npx http-server
  4. Navigate to http://localhost:8080/example/index.html

License

MIT