Ir al contenido

TreeSelect

Selección de árbol desplegable para datos jerárquicos.

import { TreeSelect } from 'asterui'
import type { TreeDataNode } from 'asterui'

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
PropiedadDescripciónTipoPredeterminado
treeDataEstructura de datos del árbolTreeDataNode[][]
valueValor(es) seleccionado(s)string | string[]-
defaultValueValor(es) seleccionado(s) predeterminado(s)string | string[][]
onChangeCallback cuando cambia la selección(value: string | string[], labels: ReactNode[]) => void-
multiplePermitir selección múltiplebooleanfalse
treeCheckableMostrar checkbox para nodos del árbolbooleanfalse
treeCheckStrictlyMarcar sin asociación padre-hijobooleanfalse
showCheckedStrategyCómo mostrar elementos marcados'SHOW_ALL' | 'SHOW_PARENT' | 'SHOW_CHILD''SHOW_ALL'
showSearchHabilitar funcionalidad de búsquedabooleanfalse
searchValueValor de entrada de búsqueda controladostring-
onSearchCallback cuando cambia la entrada de búsqueda(value: string) => void-
filterTreeNodeFunción de filtro personalizada(searchValue: string, node: TreeDataNode) => boolean-
placeholderTexto de placeholderstring'Please select'
allowClearMostrar botón de limpiarbooleantrue
disabledDeshabilitar el selectbooleanfalse
sizeTamaño del input'xs' | 'sm' | 'md' | 'lg' | 'xl''md'
colorTema de color'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'error'-
statusEstado de validación'error' | 'warning'-
maxTagCountNúmero máximo de etiquetas a mostrarnumber | 'responsive'-
maxTagPlaceholderContenido para etiquetas ocultasReactNode | ((omittedValues: string[]) => ReactNode)-
treeLineMostrar líneas conectorasbooleanfalse
treeDefaultExpandAllExpandir todos los nodos del árbol por defectobooleanfalse
treeDefaultExpandedKeysClaves de nodos del árbol expandidas por defectostring[][]
treeExpandedKeysClaves de nodos del árbol expandidas controladasstring[]-
onTreeExpandCallback cuando los nodos del árbol se expanden/contraen(expandedKeys: string[]) => void-
loadDataCargar datos asincrónicamente(node: TreeDataNode) => Promise<void>-
fieldNamesPersonalizar nombres de campo{ label?: string; value?: string; children?: string }-
openVisibilidad del desplegable controladaboolean-
onDropdownVisibleChangeCallback cuando cambia la visibilidad del desplegable(open: boolean) => void-
suffixIconIcono de sufijo personalizadoReactNode-
switcherIconIcono personalizado de expandir/contraerReactNode | ((props: { expanded: boolean }) => ReactNode)-
notFoundContentContenido cuando no hay resultadosReactNode'No results found'
dropdownRenderRenderizador de contenido del desplegable personalizado(menu: ReactNode) => ReactNode-
popupClassNameClase para el desplegablestring-
data-testidID de prueba para el componentestring'treeselect'
classNameClases CSS adicionalesstring-
PropiedadDescripciónTipoPredeterminado
keyIdentificador únicostring-
titleTexto de visualizaciónReactNode-
childrenNodos hijosTreeDataNode[]-
disabledSi está deshabilitadoboolean-
isLeafSi es un nodo hojaboolean-

El componente TreeSelect sigue los patrones de combobox y árbol WAI-ARIA con atributos ARIA adecuados y navegación por teclado.

TeclaAcción
Enter / SpaceAbrir desplegable o seleccionar elemento enfocado
EscapeCerrar 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
HomeMover foco al primer elemento
EndMover foco al último elemento

El componente expone atributos data-testid y data-state para pruebas:

ElementoTest IDAtributos 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.