Checkbox with controlled selectedIds
This example demonstrates how to create a checkbox tree
- Drinks-7
- Vegetables-16
import React, { useState } from "react";
import { FaSquare, FaCheckSquare, FaMinusSquare } from "react-icons/fa";
import { IoMdArrowDropright } from "react-icons/io";
import TreeView, { flattenTree } from "react-accessible-treeview";
import cx from "classnames";
import "./styles.css";
const folder = {
name: "",
children: [
{
name: "Fruits",
children: [
{ name: "Avocados" },
{ name: "Bananas" },
{ name: "Berries" },
{ name: "Oranges" },
{ name: "Pears" },
],
},
{
name: "Drinks",
children: [
{ name: "Apple Juice" },
{ name: "Chocolate" },
{ name: "Coffee" },
{
name: "Tea",
children: [
{ name: "Black Tea" },
{ name: "Green Tea" },
{ name: "Red Tea" },
{ name: "Matcha" },
],
},
],
},
{
name: "Vegetables",
children: [
{ name: "Beets" },
{ name: "Carrots" },
{ name: "Celery" },
{ name: "Lettuce" },
{ name: "Onions" },
],
},
],
};
const data = flattenTree(folder);
function MultiSelectCheckboxControlled() {
const [selectedIds, setSelectedIds] = useState([]);
const onKeyDown = (e) => {
if (e.key === "Enter") {
getAndSetIds();
}
};
const getAndSetIds = () => {
setSelectedIds(
document
.querySelector("#txtIdsToSelect")
.value.split(",")
.filter(val => !!val.trim())
.map((x) => {
if (isNaN(parseInt(x.trim()))) {
return x;
}
return parseInt(x.trim());
})
);
};
return (
<div>
<div>
<label htmlFor="txtIdsToSelect">
Comma-delimited list of IDs to set:
</label>
<input id="txtIdsToSelect" type="text" onKeyDown={onKeyDown} />
<button onClick={() => getAndSetIds()}>Set</button>
</div>
<div>
<button onClick={() => setSelectedIds([])}>Clear Selected Nodes</button>
</div>
<div className="checkbox">
<TreeView
data={data}
aria-label="Checkbox tree"
multiSelect
selectedIds={selectedIds}
defaultExpandedIds={[1]}
propagateSelect
propagateSelectUpwards
togglableSelect
onSelect={(props) => console.log('onSelect callback: ', props)}
onNodeSelect={(props) => console.log('onNodeSelect callback: ', props)}
nodeRenderer={({
element,
isBranch,
isExpanded,
isSelected,
isHalfSelected,
isDisabled,
getNodeProps,
level,
handleSelect,
handleExpand,
}) => {
return (
<div
{...getNodeProps({ onClick: handleExpand })}
style={{
marginLeft: 40 * (level - 1),
opacity: isDisabled ? 0.5 : 1,
}}
>
{isBranch && <ArrowIcon isOpen={isExpanded} />}
<CheckBoxIcon
className="checkbox-icon"
onClick={(e) => {
handleSelect(e);
e.stopPropagation();
}}
variant={
isHalfSelected ? "some" : isSelected ? "all" : "none"
}
/>
<span className="name">
{element.name}-{element.id}
</span>
</div>
);
}}
/>
</div>
</div>
);
}
const ArrowIcon = ({ isOpen, className }) => {
const baseClass = "arrow";
const classes = cx(
baseClass,
{ [`${baseClass}--closed`]: !isOpen },
{ [`${baseClass}--open`]: isOpen },
className
);
return <IoMdArrowDropright className={classes} />;
};
const CheckBoxIcon = ({ variant, ...rest }) => {
switch (variant) {
case "all":
return <FaCheckSquare {...rest} />;
case "none":
return <FaSquare {...rest} />;
case "some":
return <FaMinusSquare {...rest} />;
default:
return null;
}
};
export default MultiSelectCheckboxControlled;
.checkbox {
font-size: 16px;
user-select: none;
min-height: 320px;
padding: 20px;
box-sizing: content-box;
}
.checkbox .tree,
.checkbox .tree-node,
.checkbox .tree-node-group {
list-style: none;
margin: 0;
padding: 0;
}
.checkbox .tree-branch-wrapper,
.checkbox .tree-node__leaf {
outline: none;
}
.checkbox .tree-node {
cursor: pointer;
}
.checkbox .tree-node .name:hover {
background: rgba(0, 0, 0, 0.1);
}
.checkbox .tree-node--focused .name {
background: rgba(0, 0, 0, 0.2);
}
.checkbox .tree-node {
display: inline-block;
}
.checkbox .checkbox-icon {
margin: 0 5px;
vertical-align: middle;
}
.checkbox button {
border: none;
background: transparent;
cursor: pointer;
}
.checkbox .arrow {
margin-left: 5px;
vertical-align: middle;
}
.checkbox .arrow--open {
transform: rotate(90deg);
}