TreeSelect
Selección de árbol desplegable para datos jerárquicos.
Importación
Sección titulada «Importación»import { TreeSelect } from 'asterui'import type { TreeDataNode } from 'asterui'Ejemplos
Sección titulada «Ejemplos»TreeSelect Básico
Selecciona un solo valor de una estructura de árbol.
import { TreeSelect } from 'asterui'
import type { TreeDataNode } from 'asterui'
import { useState } from 'react'
function App() {
const basicTreeData: TreeDataNode[] = [
{
key: 'parent',
title: 'Parent Node',
children: [
{
key: 'child1',
title: 'Child Node 1',
children: [
{ key: 'leaf1', title: 'Leaf 1' },
{ key: 'leaf2', title: 'Leaf 2' },
],
},
{ key: 'child2', title: 'Child Node 2' },
],
},
]
const [value, setValue] = useState<string | undefined>()
return (
<TreeSelect
treeData={basicTreeData}
value={value}
onChange={(val) => setValue(val as string)}
placeholder="Select an item"
/>
)
}
export default App Selección Múltiple
Selecciona múltiples valores del árbol.
import { TreeSelect } from 'asterui'
import type { TreeDataNode } from 'asterui'
import { useState } from 'react'
function App() {
const categoriesData: TreeDataNode[] = [
{
key: 'electronics',
title: 'Electronics',
children: [
{
key: 'phones',
title: 'Phones',
children: [
{ key: 'iphone', title: 'iPhone' },
{ key: 'samsung', title: 'Samsung' },
{ key: 'pixel', title: 'Pixel' },
],
},
{
key: 'laptops',
title: 'Laptops',
children: [
{ key: 'macbook', title: 'MacBook' },
{ key: 'thinkpad', title: 'ThinkPad' },
],
},
],
},
{
key: 'clothing',
title: 'Clothing',
children: [
{ key: 'shirts', title: 'Shirts' },
{ key: 'pants', title: 'Pants' },
{ key: 'shoes', title: 'Shoes' },
],
},
]
const [value, setValue] = useState<string[]>([])
return (
<TreeSelect
treeData={categoriesData}
value={value}
onChange={(val) => setValue(val as string[])}
placeholder="Select items"
multiple
/>
)
}
export default App Con Checkbox
Usa checkboxes para selección con asociación padre-hijo.
import { TreeSelect } from 'asterui'
import type { TreeDataNode } from 'asterui'
import { useState } from 'react'
function App() {
const categoriesData: TreeDataNode[] = [
{
key: 'electronics',
title: 'Electronics',
children: [
{
key: 'phones',
title: 'Phones',
children: [
{ key: 'iphone', title: 'iPhone' },
{ key: 'samsung', title: 'Samsung' },
{ key: 'pixel', title: 'Pixel' },
],
},
{
key: 'laptops',
title: 'Laptops',
children: [
{ key: 'macbook', title: 'MacBook' },
{ key: 'thinkpad', title: 'ThinkPad' },
],
},
],
},
{
key: 'clothing',
title: 'Clothing',
children: [
{ key: 'shirts', title: 'Shirts' },
{ key: 'pants', title: 'Pants' },
{ key: 'shoes', title: 'Shoes' },
],
},
]
const [value, setValue] = useState<string[]>([])
return (
<TreeSelect
treeData={categoriesData}
value={value}
onChange={(val) => setValue(val as string[])}
placeholder="Check items"
treeCheckable
/>
)
}
export default App Buscable
Filtra nodos del árbol con búsqueda.
import { TreeSelect } from 'asterui'
import type { TreeDataNode } from 'asterui'
import { useState } from 'react'
function App() {
const categoriesData: TreeDataNode[] = [
{
key: 'electronics',
title: 'Electronics',
children: [
{
key: 'phones',
title: 'Phones',
children: [
{ key: 'iphone', title: 'iPhone' },
{ key: 'samsung', title: 'Samsung' },
{ key: 'pixel', title: 'Pixel' },
],
},
{
key: 'laptops',
title: 'Laptops',
children: [
{ key: 'macbook', title: 'MacBook' },
{ key: 'thinkpad', title: 'ThinkPad' },
],
},
],
},
{
key: 'clothing',
title: 'Clothing',
children: [
{ key: 'shirts', title: 'Shirts' },
{ key: 'pants', title: 'Pants' },
{ key: 'shoes', title: 'Shoes' },
],
},
]
const [value, setValue] = useState<string | undefined>()
return (
<TreeSelect
treeData={categoriesData}
value={value}
onChange={(val) => setValue(val as string)}
placeholder="Search and select"
showSearch
/>
)
}
export default App Tamaños
TreeSelect viene en varios tamaños.
import { TreeSelect } from 'asterui'
import type { TreeDataNode } from 'asterui'
function App() {
const simpleData: TreeDataNode[] = [
{ key: 'opt1', title: 'Option 1' },
{ key: 'opt2', title: 'Option 2' },
{ key: 'opt3', title: 'Option 3' },
]
return (
<div className="flex flex-col gap-2">
<TreeSelect treeData={simpleData} size="xs" placeholder="Extra small" />
<TreeSelect treeData={simpleData} size="sm" placeholder="Small" />
<TreeSelect treeData={simpleData} size="md" placeholder="Medium" />
<TreeSelect treeData={simpleData} size="lg" placeholder="Large" />
<TreeSelect treeData={simpleData} size="xl" placeholder="Extra large" />
</div>
)
}
export default App Estado de Validación
Muestra estados de error o advertencia.
import { TreeSelect } from 'asterui'
import type { TreeDataNode } from 'asterui'
function App() {
const simpleData: TreeDataNode[] = [
{ key: 'opt1', title: 'Option 1' },
{ key: 'opt2', title: 'Option 2' },
{ key: 'opt3', title: 'Option 3' },
]
return (
<div className="flex flex-col gap-2">
<TreeSelect treeData={simpleData} status="error" placeholder="Error state" />
<TreeSelect treeData={simpleData} status="warning" placeholder="Warning state" />
</div>
)
}
export default App Carga Asíncrona
Carga nodos del árbol asincrónicamente al expandir.
import { TreeSelect } from 'asterui'
import type { TreeDataNode } from 'asterui'
import { useState } from 'react'
function App() {
const [treeData, setTreeData] = useState<TreeDataNode[]>([
{ key: 'region1', title: 'Region 1' },
{ key: 'region2', title: 'Region 2' },
])
const loadData = async (node: TreeDataNode) => {
await new Promise((resolve) => setTimeout(resolve, 1000))
setTreeData((prev) => {
const updateNode = (nodes: TreeDataNode[]): TreeDataNode[] =>
nodes.map((n) =>
n.key === node.key
? {
...n,
children: [
{ key: `${n.key}-1`, title: 'Child 1', isLeaf: true },
{ key: `${n.key}-2`, title: 'Child 2', isLeaf: true },
],
}
: { ...n, children: n.children ? updateNode(n.children) : undefined }
)
return updateNode(prev)
})
}
return (
<TreeSelect
treeData={treeData}
loadData={loadData}
placeholder="Expand to load"
/>
)
}
export default App Límite de Etiquetas
Limita el número de etiquetas visibles.
import { TreeSelect } from 'asterui'
import type { TreeDataNode } from 'asterui'
import { useState } from 'react'
function App() {
const categoriesData: TreeDataNode[] = [
{
key: 'electronics',
title: 'Electronics',
children: [
{
key: 'phones',
title: 'Phones',
children: [
{ key: 'iphone', title: 'iPhone' },
{ key: 'samsung', title: 'Samsung' },
{ key: 'pixel', title: 'Pixel' },
],
},
{
key: 'laptops',
title: 'Laptops',
children: [
{ key: 'macbook', title: 'MacBook' },
{ key: 'thinkpad', title: 'ThinkPad' },
],
},
],
},
{
key: 'clothing',
title: 'Clothing',
children: [
{ key: 'shirts', title: 'Shirts' },
{ key: 'pants', title: 'Pants' },
{ key: 'shoes', title: 'Shoes' },
],
},
]
const [value, setValue] = useState<string[]>([])
return (
<TreeSelect
treeData={categoriesData}
value={value}
onChange={(val) => setValue(val as string[])}
placeholder="Select items"
treeCheckable
maxTagCount={2}
maxTagPlaceholder={(omitted) => `+${omitted.length} more...`}
/>
)
}
export default App Línea de Árbol
Muestra líneas conectoras entre nodos del árbol.
import { TreeSelect } from 'asterui'
import type { TreeDataNode } from 'asterui'
function App() {
const basicTreeData: TreeDataNode[] = [
{
key: 'parent',
title: 'Parent Node',
children: [
{
key: 'child1',
title: 'Child Node 1',
children: [
{ key: 'leaf1', title: 'Leaf 1' },
{ key: 'leaf2', title: 'Leaf 2' },
],
},
{ key: 'child2', title: 'Child Node 2' },
],
},
]
return (
<TreeSelect
treeData={basicTreeData}
placeholder="With tree lines"
treeLine
treeDefaultExpandAll
/>
)
}
export default App Elementos Deshabilitados
Algunos nodos del árbol pueden estar deshabilitados.
import { TreeSelect } from 'asterui'
import type { TreeDataNode } from 'asterui'
import { useState } from 'react'
function App() {
const [value, setValue] = useState<string | undefined>()
const treeDataWithDisabled: TreeDataNode[] = [
{
key: 'parent',
title: 'Available Parent',
children: [
{ key: 'child1', title: 'Available Child' },
{ key: 'child2', title: 'Disabled Child', disabled: true },
{ key: 'child3', title: 'Another Available' },
],
},
]
return (
<TreeSelect
treeData={treeDataWithDisabled}
value={value}
onChange={(val) => setValue(val as string)}
placeholder="Select an item"
/>
)
}
export default App TreeSelect
Sección titulada «TreeSelect»| Propiedad | Descripción | Tipo | Predeterminado |
|---|---|---|---|
treeData | Estructura de datos del árbol | TreeDataNode[] | [] |
value | Valor(es) seleccionado(s) | string | string[] | - |
defaultValue | Valor(es) seleccionado(s) predeterminado(s) | string | string[] | [] |
onChange | Callback cuando cambia la selección | (value: string | string[], labels: ReactNode[]) => void | - |
multiple | Permitir selección múltiple | boolean | false |
treeCheckable | Mostrar checkbox para nodos del árbol | boolean | false |
treeCheckStrictly | Marcar sin asociación padre-hijo | boolean | false |
showCheckedStrategy | Cómo mostrar elementos marcados | 'SHOW_ALL' | 'SHOW_PARENT' | 'SHOW_CHILD' | 'SHOW_ALL' |
showSearch | Habilitar funcionalidad de búsqueda | boolean | false |
searchValue | Valor de entrada de búsqueda controlado | string | - |
onSearch | Callback cuando cambia la entrada de búsqueda | (value: string) => void | - |
filterTreeNode | Función de filtro personalizada | (searchValue: string, node: TreeDataNode) => boolean | - |
placeholder | Texto de placeholder | string | 'Please select' |
allowClear | Mostrar botón de limpiar | boolean | true |
disabled | Deshabilitar el select | boolean | false |
size | Tamaño del input | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' |
color | Tema de color | 'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'error' | - |
status | Estado de validación | 'error' | 'warning' | - |
maxTagCount | Número máximo de etiquetas a mostrar | number | 'responsive' | - |
maxTagPlaceholder | Contenido para etiquetas ocultas | ReactNode | ((omittedValues: string[]) => ReactNode) | - |
treeLine | Mostrar líneas conectoras | boolean | false |
treeDefaultExpandAll | Expandir todos los nodos del árbol por defecto | boolean | false |
treeDefaultExpandedKeys | Claves de nodos del árbol expandidas por defecto | string[] | [] |
treeExpandedKeys | Claves de nodos del árbol expandidas controladas | string[] | - |
onTreeExpand | Callback cuando los nodos del árbol se expanden/contraen | (expandedKeys: string[]) => void | - |
loadData | Cargar datos asincrónicamente | (node: TreeDataNode) => Promise<void> | - |
fieldNames | Personalizar nombres de campo | { label?: string; value?: string; children?: string } | - |
open | Visibilidad del desplegable controlada | boolean | - |
onDropdownVisibleChange | Callback cuando cambia la visibilidad del desplegable | (open: boolean) => void | - |
suffixIcon | Icono de sufijo personalizado | ReactNode | - |
switcherIcon | Icono personalizado de expandir/contraer | ReactNode | ((props: { expanded: boolean }) => ReactNode) | - |
notFoundContent | Contenido cuando no hay resultados | ReactNode | 'No results found' |
dropdownRender | Renderizador de contenido del desplegable personalizado | (menu: ReactNode) => ReactNode | - |
popupClassName | Clase para el desplegable | string | - |
data-testid | ID de prueba para el componente | string | 'treeselect' |
className | Clases CSS adicionales | string | - |
TreeDataNode
Sección titulada «TreeDataNode»| Propiedad | Descripción | Tipo | Predeterminado |
|---|---|---|---|
key | Identificador único | string | - |
title | Texto de visualización | ReactNode | - |
children | Nodos hijos | TreeDataNode[] | - |
disabled | Si está deshabilitado | boolean | - |
isLeaf | Si es un nodo hoja | boolean | - |
Accesibilidad
Sección titulada «Accesibilidad»El componente TreeSelect sigue los patrones de combobox y árbol WAI-ARIA con atributos ARIA adecuados y navegación por teclado.
Navegación por Teclado
Sección titulada «Navegación por Teclado»| Tecla | Acción |
|---|---|
| Enter / Space | Abrir desplegable o seleccionar elemento enfocado |
| Escape | Cerrar desplegable |
| ↓ | Abrir desplegable o mover foco hacia abajo |
| ↑ | Mover foco hacia arriba |
| → | Expandir nodo del árbol enfocado |
| ← | Contraer nodo del árbol enfocado o mover al padre |
| Home | Mover foco al primer elemento |
| End | Mover foco al último elemento |
Pruebas
Sección titulada «Pruebas»El componente expone atributos data-testid y data-state para pruebas:
| Elemento | Test ID | Atributos de Datos |
|---|---|---|
| Raíz | {baseTestId} | data-state="open|closed", data-disabled |
| Disparador | {baseTestId}-trigger | - |
| Desplegable | {baseTestId}-dropdown | - |
| Búsqueda | {baseTestId}-search | - |
| Limpiar | {baseTestId}-clear | - |
| Opción | {baseTestId}-option-{key} | data-state="selected|unselected", data-disabled |
| Etiqueta | {baseTestId}-tag-{key} | - |
| Vacío | {baseTestId}-empty | - |
Pasa una prop data-testid personalizada para usar un ID base diferente.