# Component/Tree > Props: component-tree.props.txt ## Examples ### Async ```tsx { render: () => { const [items, setItems] = useState([{ id: 'item-1', label: 'Node 1', hasChildren: true }, { id: 'item-2', label: 'Node 2', hasChildren: true }, { id: 'item-3', label: 'Node 3' }]); function update(tree: TreeEntry[], id: string, value: TreeEntry): TreeEntry[] { return tree.map(item => { if (item.id === id) { return value; } return { ...item, children: update(item.children ?? [], id, value) }; }); } const [selected, setSelected] = useState(null); return { setSelected(item.id); }} onExpand={item => { if (item.hasChildren && !item.loading) { setItems(update(items, item.id, { ...item, loading: true })); setTimeout(() => { setItems(update(items, item.id, { ...item, loading: false, hasChildren: undefined, children: [{ id: `${item.id}-1`, label: 'Node 1', hasChildren: true }, { id: `${item.id}-2`, label: 'Node 2', hasChildren: true }, { id: `${item.id}-3`, label: 'Node 3' }] })); }, 300); } }} />; } } ``` ### Checkable ```tsx { args: { checkable: true, items: [{ id: 'fruit', label: 'Fruit', children: [{ id: 'apple', label: 'Apple' }, { id: 'banana', label: 'Banana' }, { id: 'citrus', label: 'Citrus', children: [{ id: 'orange', label: 'Orange' }, { id: 'lemon', label: 'Lemon' }] }] }, { id: 'vegetables', label: 'Vegetables', children: [{ id: 'leafy', label: 'Leafy Greens', children: [{ id: 'spinach', label: 'Spinach', actionIcon: , action: 'Action' }, { id: 'kale', label: 'Kale' }] }, { id: 'root', label: 'Root Vegetables', children: [{ id: 'carrot', label: 'Carrot' }, { id: 'beet', label: 'Beetroot' }] }] }, { id: 'desserts', label: 'Desserts', children: [{ id: 'cake', label: 'Cake' }, { id: 'icecream', label: 'Ice Cream', children: [{ id: 'vanilla', label: 'Vanilla' }, { id: 'chocolate', label: 'Chocolate' }, { id: 'veryverylong', label: 'Strawberry Marshmallow SuperMegaUltraSupremeSwirlDeliciousConfetti Explosion XL' }, { id: 'veryverylong2', label: 'ChocolateFudgeSuperMegaUltraHyperDeliciousRainbowSprinkleGalaxyExplosionDelight XXL', actionIcon: , action: 'Action' }] }] }] }, render: args => { const [checkedIds, setCheckedIds] = useState([]); return
Checked IDs: {checkedIds.length > 0 && checkedIds.join(', ')}
{ setCheckedIds(checked_ids); }} />
; } } ``` ### Checkable With Default Expanded Ids ```tsx { args: { checkable: true, items: [{ id: 'fruit', label: 'Fruit', children: [{ id: 'apple', label: 'Apple' }, { id: 'banana', label: 'Banana' }, { id: 'citrus', label: 'Citrus', children: [{ id: 'orange', label: 'Orange' }, { id: 'lemon', label: 'Lemon' }] }] }, { id: 'vegetables', label: 'Vegetables', children: [{ id: 'leafy', label: 'Leafy Greens', children: [{ id: 'spinach', label: 'Spinach', actionIcon: , action: 'Action' }, { id: 'kale', label: 'Kale' }] }, { id: 'root', label: 'Root Vegetables', children: [{ id: 'carrot', label: 'Carrot' }, { id: 'beet', label: 'Beetroot' }] }] }, { id: 'desserts', label: 'Desserts', children: [{ id: 'cake', label: 'Cake' }, { id: 'icecream', label: 'Ice Cream', children: [{ id: 'vanilla', label: 'Vanilla' }, { id: 'chocolate', label: 'Chocolate' }, { id: 'veryverylong', label: 'Strawberry Marshmallow SuperMegaUltraSupremeSwirlDeliciousConfetti Explosion XL' }, { id: 'veryverylong2', label: 'ChocolateFudgeSuperMegaUltraHyperDeliciousRainbowSprinkleGalaxyExplosionDelight XXL', actionIcon: , action: 'Action' }] }] }] }, render: args => { const [checkedIds, setCheckedIds] = useState([]); return
Checked IDs: {checkedIds.length > 0 && checkedIds.join(', ')}
{ setCheckedIds(checked_ids); }} />
; }, render: args => { const [checkedIds, setCheckedIds] = useState(['orange']); const defaultExpandedIds = useMemo(() => ['orange'], []); return
Checked IDs: {checkedIds.length > 0 && checkedIds.join(', ')}
{ setCheckedIds(items.map(item => item.id)); }} />
; } } ``` ### Default Expand ```tsx { args: { items: [{ id: 'fruit', label: 'Fruit', children: [{ id: 'apple', label: 'Apple' }, { id: 'banana', label: 'Banana' }, { id: 'citrus', label: 'Citrus', children: [{ id: 'orange', label: 'Orange' }, { id: 'lemon', label: 'Lemon' }] }] }, { id: 'vegetables', label: 'Vegetables', children: [{ id: 'leafy', label: 'Leafy Greens', children: [{ id: 'spinach', label: 'Spinach', actionIcon: , action: 'Action' }, { id: 'kale', label: 'Kale', loading: true }] }, { id: 'root', label: 'Root Vegetables', children: [{ id: 'carrot', label: 'Carrot' }, { id: 'beet', label: 'Beetroot' }] }] }, { id: 'desserts', label: 'Desserts', children: [{ id: 'cake', label: 'Cake' }, { id: 'icecream', label: 'Ice Cream', children: [{ id: 'vanilla', label: 'Vanilla' }, { id: 'chocolate', label: 'Chocolate' }, { id: 'veryverylong', label: 'Strawberry Marshmallow SuperMegaUltraSupremeSwirlDeliciousConfetti Explosion XL' }, { id: 'veryverylong2', label: 'ChocolateFudgeSuperMegaUltraHyperDeliciousRainbowSprinkleGalaxyExplosionDelight XXL', actionIcon: , action: 'Action' }] }] }, { id: 'loading', label: 'Loading', loading: true }, { id: 'action', label: 'Action', actionIcon: , action: 'Action' }] }, render: args => { const [selected, setSelected] = useState(null); const defaultExpandedIds = useMemo(() => ['veryverylong', 'kale'], []); return { if (item.children == null || item.children.length === 0) { setSelected(item.id); } }} />; } } ``` ### Primary ```tsx { args: { items: [{ id: 'fruit', label: 'Fruit', children: [{ id: 'apple', label: 'Apple' }, { id: 'banana', label: 'Banana' }, { id: 'citrus', label: 'Citrus', children: [{ id: 'orange', label: 'Orange' }, { id: 'lemon', label: 'Lemon' }] }] }, { id: 'vegetables', label: 'Vegetables', children: [{ id: 'leafy', label: 'Leafy Greens', children: [{ id: 'spinach', label: 'Spinach', actionIcon: , action: 'Action' }, { id: 'kale', label: 'Kale', loading: true }] }, { id: 'root', label: 'Root Vegetables', children: [{ id: 'carrot', label: 'Carrot' }, { id: 'beet', label: 'Beetroot' }] }] }, { id: 'desserts', label: 'Desserts', children: [{ id: 'cake', label: 'Cake' }, { id: 'icecream', label: 'Ice Cream', children: [{ id: 'vanilla', label: 'Vanilla' }, { id: 'chocolate', label: 'Chocolate' }, { id: 'veryverylong', label: 'Strawberry Marshmallow SuperMegaUltraSupremeSwirlDeliciousConfetti Explosion XL' }, { id: 'veryverylong2', label: 'ChocolateFudgeSuperMegaUltraHyperDeliciousRainbowSprinkleGalaxyExplosionDelight XXL', actionIcon: , action: 'Action' }] }] }, { id: 'loading', label: 'Loading', loading: true }, { id: 'action', label: 'Action', actionIcon: , action: 'Action' }] } } ``` ### Search ```tsx { args: { items: [{ id: 'fruit', label: 'Fruit', children: [{ id: 'apple', label: 'Apple' }, { id: 'banana', label: 'Banana' }, { id: 'citrus', label: 'Citrus', children: [{ id: 'orange', label: 'Orange' }, { id: 'lemon', label: 'Lemon' }] }] }, { id: 'vegetables', label: 'Vegetables', children: [{ id: 'leafy', label: 'Leafy Greens', children: [{ id: 'spinach', label: 'Spinach', actionIcon: , action: 'Action' }, { id: 'kale', label: 'Kale', loading: true }] }, { id: 'root', label: 'Root Vegetables', children: [{ id: 'carrot', label: 'Carrot' }, { id: 'beet', label: 'Beetroot' }] }] }, { id: 'desserts', label: 'Desserts', children: [{ id: 'cake', label: 'Cake' }, { id: 'icecream', label: 'Ice Cream', children: [{ id: 'vanilla', label: 'Vanilla' }, { id: 'chocolate', label: 'Chocolate' }, { id: 'veryverylong', label: 'Strawberry Marshmallow SuperMegaUltraSupremeSwirlDeliciousConfetti Explosion XL' }, { id: 'veryverylong2', label: 'ChocolateFudgeSuperMegaUltraHyperDeliciousRainbowSprinkleGalaxyExplosionDelight XXL', actionIcon: , action: 'Action' }] }] }, { id: 'loading', label: 'Loading', loading: true }, { id: 'action', label: 'Action', actionIcon: , action: 'Action' }] }, render: args => { const [keyword, setKeyword] = useState(''); const [selected, setSelected] = useState(null); return setKeyword(e.currentTarget.value)} placeholder='검색어 입력' startElement={} /> { if (item.children == null || item.children.length === 0) { setSelected(item.id); } }} /> ; } } ``` ### Select ```tsx { args: { items: [{ id: 'fruit', label: 'Fruit', children: [{ id: 'apple', label: 'Apple' }, { id: 'banana', label: 'Banana' }, { id: 'citrus', label: 'Citrus', children: [{ id: 'orange', label: 'Orange' }, { id: 'lemon', label: 'Lemon' }] }] }, { id: 'vegetables', label: 'Vegetables', children: [{ id: 'leafy', label: 'Leafy Greens', children: [{ id: 'spinach', label: 'Spinach', actionIcon: , action: 'Action' }, { id: 'kale', label: 'Kale', loading: true }] }, { id: 'root', label: 'Root Vegetables', children: [{ id: 'carrot', label: 'Carrot' }, { id: 'beet', label: 'Beetroot' }] }] }, { id: 'desserts', label: 'Desserts', children: [{ id: 'cake', label: 'Cake' }, { id: 'icecream', label: 'Ice Cream', children: [{ id: 'vanilla', label: 'Vanilla' }, { id: 'chocolate', label: 'Chocolate' }, { id: 'veryverylong', label: 'Strawberry Marshmallow SuperMegaUltraSupremeSwirlDeliciousConfetti Explosion XL' }, { id: 'veryverylong2', label: 'ChocolateFudgeSuperMegaUltraHyperDeliciousRainbowSprinkleGalaxyExplosionDelight XXL', actionIcon: , action: 'Action' }] }] }, { id: 'loading', label: 'Loading', loading: true }, { id: 'action', label: 'Action', actionIcon: , action: 'Action' }] }, render: args => { const [selected, setSelected] = useState(null); return { if (item.children == null || item.children.length === 0) { setSelected(item.id); } }} /> ; } } ``` ### Separate Expand And Select `shouldExpandOnSelect={false}`로 두면 행 클릭은 선택만 하고, 확장/접힘은 좌측 화살표 아이콘 클릭(또는 키보드 방향키)으로만 동작합니다. 카테고리(부모 항목)를 선택 상태로 유지하면서 하위 항목을 접거나 펼치고 싶을 때 사용합니다. ```tsx { args: { items: [{ id: 'fruit', label: 'Fruit', children: [{ id: 'apple', label: 'Apple' }, { id: 'banana', label: 'Banana' }, { id: 'citrus', label: 'Citrus', children: [{ id: 'orange', label: 'Orange' }, { id: 'lemon', label: 'Lemon' }] }] }, { id: 'vegetables', label: 'Vegetables', children: [{ id: 'leafy', label: 'Leafy Greens', children: [{ id: 'spinach', label: 'Spinach', actionIcon: , action: 'Action' }, { id: 'kale', label: 'Kale', loading: true }] }, { id: 'root', label: 'Root Vegetables', children: [{ id: 'carrot', label: 'Carrot' }, { id: 'beet', label: 'Beetroot' }] }] }, { id: 'desserts', label: 'Desserts', children: [{ id: 'cake', label: 'Cake' }, { id: 'icecream', label: 'Ice Cream', children: [{ id: 'vanilla', label: 'Vanilla' }, { id: 'chocolate', label: 'Chocolate' }, { id: 'veryverylong', label: 'Strawberry Marshmallow SuperMegaUltraSupremeSwirlDeliciousConfetti Explosion XL' }, { id: 'veryverylong2', label: 'ChocolateFudgeSuperMegaUltraHyperDeliciousRainbowSprinkleGalaxyExplosionDelight XXL', actionIcon: , action: 'Action' }] }] }, { id: 'loading', label: 'Loading', loading: true }, { id: 'action', label: 'Action', actionIcon: , action: 'Action' }] }, parameters: { docs: { description: { story: ['`shouldExpandOnSelect={false}`로 두면 행 클릭은 선택만 하고, 확장/접힘은 좌측 화살표 아이콘 클릭(또는 키보드 방향키)으로만 동작합니다.', '카테고리(부모 항목)를 선택 상태로 유지하면서 하위 항목을 접거나 펼치고 싶을 때 사용합니다.'].join('\n') } } }, render: args => { const [selected, setSelected] = useState(null); // 확장 상태를 selectedIds와 분리(고정값)해 선택이 자동 확장을 유발하지 않게 한다. const defaultExpandedIds = useMemo(() => ['fruit', 'vegetables'], []); return setSelected(item.id)} />; } } ```