A flexible, headless React tree component library that provides powerful tree state management with render props pattern.
- π― Headless Design - Complete control over rendering and styling
- π§ Flexible API - Use
Tree
,VirtualizedTree
components or build custom solutions withuseTreeState
,flattenTree
- π¦ TypeScript Support - Fully typed for better developer experience
- π Performance - Efficient tree flattening and state management
- β‘ Virtualization - Handle massive datasets (300,000+ items) with smooth scrolling performance
- π¨ Render Props - Flexible rendering with full access to tree state
- π³ Deep Nesting - Support for deeply nested tree structures (10+ levels)
npm install @kryoonminsang/headless-tree
yarn add @kryoonminsang/headless-tree
pnpm add @kryoonminsang/headless-tree
import { Tree } from '@kryoonminsang/headless-tree';
<Tree
initialTree={treeData}
renderItem={({ item, depth, toggleOpenState }) => (
<div style={{ paddingLeft: depth * 20 }}>
<button onClick={toggleOpenState}>{item.isOpened ? 'π' : 'π'}</button>
{item.customData.name}
</div>
)}
/>;
import { VirtualizedTree } from '@kryoonminsang/headless-tree';
<VirtualizedTree
initialTree={largeTreeData}
height="400px"
estimateSize={() => 32}
renderItem={({ item, depth, toggleOpenState }) => (
<div style={{ paddingLeft: depth * 16, height: 32 }}>
<button onClick={toggleOpenState}>{item.isOpened ? 'π' : 'π'}</button>
{item.customData.name}
</div>
)}
/>;
import { useRef } from 'react';
import { Tree, TreeRef } from '@kryoonminsang/headless-tree';
function ControlledTree() {
const treeRef = useRef<TreeRef>(null);
return (
<>
<button onClick={() => treeRef.current?.openAll()}>
Expand All
</button>
<Tree ref={treeRef} initialTree={treeData} renderItem={...} />
</>
);
}
interface FileItem {
name: string;
type: 'file' | 'folder';
}
const treeData = {
rootIds: ['1', '2'],
items: {
'1': {
id: '1',
children: ['1-1'],
customData: { name: 'src', type: 'folder' },
},
'1-1': {
id: '1-1',
children: [],
customData: { name: 'index.ts', type: 'file' },
},
'2': {
id: '2',
children: [],
customData: { name: 'package.json', type: 'file' },
},
},
};
Basic tree component for standard use cases.
<Tree
initialTree={treeData}
options={{ syncWithInitialTree?: boolean }}
renderItem={(params: RenderItemParams) => ReactNode}
/>
Virtualized tree component for large datasets.
<VirtualizedTree
initialTree={treeData}
height={number | string}
estimateSize={(index: number) => number}
overscan={number}
options={{ syncWithInitialTree?: boolean }}
renderItem={(params: RenderItemParams) => ReactNode}
// ... any div props (className, style, etc.)
/>
Props:
height
- Height of the virtualized containerestimateSize
- Function returning estimated height of each itemoverscan
- Number of items to render outside visible area (default: 5)- All standard HTML div props are supported
const { tree, open, close, toggleOpen, openAll, closeAll } = useTreeState({ initialTree, options });
const flattenedItems = flattenTree(tree);
// Returns: Array<{ item, depth, parentId, isLastTreeInSameDepth, completeDepthHashTable }>
const treeRef = useRef<TreeRef<YourDataType>>(null);
// Access: tree, open, close, toggleOpen, openAll, closeAll
const treeRef = useRef<VirtualizedTreeRef<YourDataType>>(null);
// Access: tree, open, close, toggleOpen, openAll, closeAll, virtualizer
This library is fully typed with TypeScript. All types are exported and can be imported:
import type {
TreeData,
BasicTreeItem,
RenderItemParams,
TreeItemId,
VirtualizedTreeProps,
VirtualizedTreeRef,
} from '@kryoonminsang/headless-tree';
We welcome contributions! Please feel free to submit a Pull Request.
- 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
# Install dependencies
pnpm install
# Run development server
pnpm dev
# Run tests
pnpm test
# Run linter
pnpm lint
# Build library
pnpm build
This project is licensed under the MIT License - see the LICENSE file for details.
If you encounter any issues or have feature requests, please create an issue on GitHub Issues.