React Folder Tree
A versatile and customizable react treeview library. Features:
β
custom icons
β
custom event handlers
β
inline add, modify, and delete tree nodes
β
checkbox with half check (indeterminate check)
β
read-only mode
It uses use-tree-state hook internally for convenient state management.
Quick Preview
Live Demos
live demos and code examples can be found here
Basic Usage
π install
$ yarn add react-folder-tree
$ npm install react-folder-tree --save
π basic tree
import FolderTree, { testData } from 'react-folder-tree';
import 'react-folder-tree/dist/style.css';
const BasicTree = () => {
const onTreeStateChange = (state, event) => console.log(state, event);
return (
<FolderTree
data={ testData }
onChange={ onTreeStateChange }
/>
);
};
π custom initial state
Initial tree state is an object that describes a nested tree node structure, which looks like:
{
// reserved keys, can customize initial value
name: 'root node',
checked (optional): 0 (unchecked, default) | 0.5 (half checked) | 1(checked),
isOpen (optional): true (default) | false,
children (optional): [array of treenode],
// internal keys (auto generated), plz don't include them in the initial data
path: [], // path is an array of indexes to this node from root node
_id: 0,
// not reserved, can carry any extra info about this node
nickname (optional): 'pikachu',
url (optional): 'url of this node',
}
checked
and isOpen
status could be auto initialized by props initCheckedStatus
and initOpenStatus
. We can also provide data with custom checked
and isOpen
status, and set initCheckedStatus
and initOpenStatus
to 'custom'
.
This example shows how to render a tree with custom initial state
const treeState = {
name: 'root [half checked and opened]',
checked: 0.5, // half check: some children are checked
isOpen: true, // this folder is opened, we can see it's children
children: [
{ name: 'children 1 [not checked]', checked: 0 },
{
name: 'children 2 [half checked and not opened]',
checked: 0.5,
isOpen: false,
children: [
{ name: 'children 2-1 [not checked]', checked: 0 },
{ name: 'children 2-2 [checked]', checked: 1 },
],
},
],
};
const CustomInitState = () => (
<FolderTree
data={ treeState }
initCheckedStatus='custom' // default: 0 [unchecked]
initOpenStatus='custom' // default: 'open'
/>
);
π hate checkbox?
<FolderTree
data={ treeState }
showCheckbox={ false } // default: true
/>
π love indentation?
<FolderTree
data={ treeState }
indentPixels={ 99999 } // default: 30
/>
π read only?
we can use it as a classical view-only tree
<FolderTree
data={ treeState }
showCheckbox={ false } // hiding checkbox is not required but recommended for better UX
readOnly // <== here!!
/>
Advanced Usage
π₯ sync tree state
In order to perform more complex operations, we can sync and keep track of the current tree state outside.
This example shows how to download all selected files.
const SuperApp = () => {
const [treeState, setTreeState] = useState(initState);
const onTreeStateChange = (state, event) => setTreeState(state);
const onDownload = () => downloadAllSelected(treeState);
return (
<>
<FolderTree
data={ initState }
onChange={ onTreeStateChange }
/>
<DownloadButton onClick={ onDownload } />
</>
);
};
π₯ custom icons
There are 9 icons and all of them are customizable.
- FileIcon
- FolderIcon
- FolderOpenIcon
- EditIcon
- DeleteIcon
- CancelIcon
- CaretRightIcon
- CaretDownIcon
- OKIcon
This example shows how to customize the FileIcon (same interface for all other icons).
import { FaBitcoin } from 'react-icons/fa';
const BitcoinApp = () => {
const FileIcon = ({ onClick: defaultOnClick, nodeData }) => {
const {
path,
name,
checked,
isOpen,
...restData
} = nodeData;
// custom event handler
const handleClick = () => {
doSthBad({ path, name, checked, isOpen, ...restData });
defaultOnClick();
};
// custom Style
return <FaBitcoin onClick={ handleClick } />;
};
return (
<FolderTree
data={ initState }
iconComponents={{
FileIcon,
/* other custom icons ... */
}}
/>
);
};
π₯ hide icons / disable interaction
This usage is a subset of custom icons.
For example, if we want to disable editing, we can hide EditIcon
by passing in a dummy custom icon, so nothing will be rendered.
const EditIcon = (...args) => null;
A little more complex but more flexible way is to have extra node data, say editable
, then build a custom icon that utilize this data
const EditIcon = ({ onClick: defaultOnClick, nodeData }) => {
const { editable } = nodeData;
// if this node is editable, render an EditIcon, otherwise render air
return editable ? (<FaEdit onClick={ defaultOnClick } />) : null;
// or render a 'not editable' icon
return editable ? (<FaEdit onClick={ defaultOnClick } />) : (<DontEdit />));
};
onClick
for node names
π₯ custom This example shows how to download the file when click on the node name.
const dataWithUrl = {
name: 'secret crypto file',
url: 'polkadot.network', // wew can provide any custom data to the FolderTree!
// ...
};
const onNameClick = ({ defaultOnClick, nodeData }) => {
defaultOnClick();
const {
// internal data
path, name, checked, isOpen,
// custom data
url, ...whateverRest
} = nodeData;
download(url);
};
const Downloader = () => (
<FolderTree
data={ dataWithUrl }
onNameClick={ onNameClick }
/>
);
APIs Summary
prop | description | type | options |
---|---|---|---|
data | initial tree state data (required) | object | N/A |
initCheckedStatus | initial check status of all nodes | string | 'unchecked' (default) | 'checked' | 'custom' |
initOpenStatus | initial open status of all treenodes | string | 'open' (default) | 'closed' | 'custom' |
iconComponents | custom icon components | object | ant design icons (default) |
onChange | callback when tree state changes | function | console.log (default) |
onNameClick | callback when click treenode name | function | open treenode inline toolbox (default) |
indentPixels | ident pixels of 1x level treenode | number | 30 (default) |
showCheckbox | show check box? | bool | true (default) |
readOnly | readOnly mode? can't click/check node | bool | false (default) |
Bugs? Questions? Contributions?
Feel free to open an issue, or create a pull request!