Primitivenavigation

Tree

Stable

Árvore composável — arquivos e pastas, uma navegação aninhada — com abrir e fechar animados, linhas-guia, ícones e seleção simples ou múltipla. Preserva a API do Kibo. O upstream era um conjunto de divs clicáveis; a normalização aplicou o padrão tree do WAI-ARIA, com uma parada de Tab e navegação por setas.

Instalação

npx up-web-ds add tree

Gera chevron-right, file, folder, folder-open para a biblioteca de ícones do projeto (components.json → iconLibrary).

Preview

Basic

app
layout.tsx
page.tsx
package.json

Nested

src
components
hooks
use-mobile.ts
utils.ts
public
package.json
README.md

Multi Select

src
components
button.tsx
dialog.tsx
tree.tsx
hooks
utils.ts
public
package.json
README.md

Selecionados: button.tsx, utils.ts

Minimal

src
components
hooks
utils.ts
public
package.json
README.md

All states

Basic

app
layout.tsx
page.tsx
package.json

Nested

src
components
hooks
use-mobile.ts
utils.ts
public
package.json
README.md

Multi Select

src
components
button.tsx
dialog.tsx
tree.tsx
hooks
utils.ts
public
package.json
README.md

Selecionados: button.tsx, utils.ts

Minimal

src
components
hooks
utils.ts
public
package.json
README.md

Usage

@/components/ui/tree
import {
  TreeExpander,
  TreeIcon,
  TreeLabel,
  TreeNode,
  TreeNodeContent,
  TreeNodeTrigger,
  TreeProvider,
  TreeView,
} from '@/components/ui/tree'
Tree
<TreeProvider className="max-w-80" defaultExpandedIds={['app']}>
  <TreeView aria-label="Arquivos do projeto">
    <TreeNode nodeId="app">
      <TreeNodeTrigger>
        <TreeExpander hasChildren />
        <TreeIcon hasChildren />
        <TreeLabel>app</TreeLabel>
      </TreeNodeTrigger>
      <TreeNodeContent hasChildren>
        <TreeNode level={1} nodeId="layout">
          <TreeNodeTrigger>
            <TreeExpander />
            <TreeIcon />
            <TreeLabel>layout.tsx</TreeLabel>
          </TreeNodeTrigger>
        </TreeNode>
        <TreeNode isLast level={1} nodeId="page">
          <TreeNodeTrigger>
            <TreeExpander />
            <TreeIcon />
            <TreeLabel>page.tsx</TreeLabel>
          </TreeNodeTrigger>
        </TreeNode>
      </TreeNodeContent>
    </TreeNode>
    <TreeNode isLast nodeId="package-json">
      <TreeNodeTrigger>
        <TreeExpander />
        <TreeIcon />
        <TreeLabel>package.json</TreeLabel>
      </TreeNodeTrigger>
    </TreeNode>
  </TreeView>
</TreeProvider>

Props

TreeProvider

Props de TreeProvider
PropTypeDefaultDescription
children, obrigatóriaReactNodesem valor padrão
animateExpandbooleantrueAnimate opening and closing.
classNamestringsem valor padrão
defaultExpandedIdsstring[][]Ids of the nodes open on the first render.
indentnumber20Indentation per level, in px.
multiSelectbooleanfalseCtrl/Cmd+click, or Space, adds to the selection instead of replacing it.
onSelectionChange((selectedIds: string[]) => void)sem valor padrão
selectablebooleantrueWhether nodes can be selected.
selectedIdsstring[]sem valor padrãoSelected ids, when controlled together with `onSelectionChange`.
showIconsbooleantrueShow `TreeIcon`.
showLinesbooleantrueDraw the guide lines between a node and its children.

TreeView

Estende HTMLAttributes<HTMLDivElement>. Aceita também os atributos padrão de um elemento React (278 não listados).

TreeNode

Props de TreeNode
PropTypeDefaultDescription
isLastbooleanfalseLast child of its parent -- the guide line stops at it.
levelnumber0Depth, from 0 at the root.
nodeIdstringsem valor padrão
parentPathboolean[][]

Estende HTMLAttributes<HTMLDivElement>. Aceita também os atributos padrão de um elemento React (278 não listados).

TreeNodeTrigger

Estende ComponentProps<typeof motion.div>. Aceita também os atributos padrão de um elemento React (67 não listados).

TreeNodeContent

Props de TreeNodeContent
PropTypeDefaultDescription
hasChildrenbooleanfalseThe node has children. Without it nothing renders.

Estende ComponentProps<typeof motion.div>. Aceita também os atributos padrão de um elemento React (67 não listados).

TreeExpander

Props de TreeExpander
PropTypeDefaultDescription
hasChildrenbooleanfalseThe node has children. Without it, a spacer the chevron's size.

Estende ComponentProps<typeof motion.div>. Aceita também os atributos padrão de um elemento React (67 não listados).

TreeIcon

Props de TreeIcon
PropTypeDefaultDescription
hasChildrenbooleanfalseThe node has children: a folder, open or closed, instead of a file.
iconReactNodesem valor padrãoReplaces the default folder/file icon.

Estende ComponentProps<typeof motion.div>. Aceita também os atributos padrão de um elemento React (67 não listados).

TreeLabel

Estende HTMLAttributes<HTMLSpanElement>. Aceita também os atributos padrão de um elemento React (278 não listados).

prop obrigatória.

Composition

O TreeProvider guarda o estado e envolve o TreeView, que é a árvore. Cada TreeNode tem uma linha (TreeNodeTrigger) e, quando tem filhos, um TreeNodeContent com os TreeNodes do nível seguinte.

Composição de TreeProvider

TreeProvider

  • TreeView
    • TreeNode
      • TreeNodeTrigger
        • TreeExpander
        • TreeIcon
        • TreeLabel
      • TreeNodeContent
        • TreeNode

Metadata

Notas de acessibilidade

Verificado em tests/e2e/tree.spec.ts no Chromium desktop e mobile, em light e dark, com Axe sem violações WCAG 2.2 AA. Teclado (padrão tree do WAI-ARIA APG): a árvore é uma parada de Tab só (roving tabindex), com anel de foco visível na linha; ArrowUp/ArrowDown percorrem os itens visíveis, Home/End vão às pontas, ArrowRight abre uma pasta fechada ou entra na aberta, ArrowLeft fecha a pasta aberta ou volta ao pai, Enter faz o que o clique faz (alternar e selecionar) e Espaço seleciona — numa árvore multiSelect, Espaço adiciona ou remove da seleção, como Ctrl/Cmd+clique. O whileTap do upstream transformava cada linha numa parada de Tab extra; o toque virou CSS (motion-safe:active:scale). Leitor de tela verificado pelo snapshot da árvore de acessibilidade do navegador: TreeView é tree nomeado pelo consumidor, cada TreeNode é treeitem nomeado pela própria linha, com aria-level, aria-expanded só quando tem filhos e aria-selected só quando a árvore é selecionável; os filhos ficam num group; aria-multiselectable na árvore múltipla; ícones e linhas-guia fora da árvore. Toque verificado em 375px com emulação de toque: cada linha passa de 24x24, o toque abre a pasta e não há rolagem horizontal. Reduced motion verificado em navegador com prefers-reduced-motion: reduce, via useReducedMotion() — a pasta abre com os filhos já na altura final, só com fade, sem deslizar; o chevron aponta para o novo lado sem girar; os empurrõezinhos de toque e hover saem. Decisão visual registrada: o fade de entrada da árvore inteira a cada montagem (300ms) foi removido — deixava todos os rótulos abaixo do contraste durante a entrada, e a varredura WCAG do catálogo o detectou; pastas abertas por defaultExpandedIds já aparecem abertas. `onSelectionChange` passou a ser chamado também sem `selectedIds` (o upstream o ignorava nesse caso).

Classificação

Layer
Primitive
Domínio
Domain-free (compartilhado)
Categoria
navigation
Status
Stable

Origem e distribuição

Fonte
kibo registry / tree
Licença
MIT
Distribuição
Interna

Acessibilidade

  • Teclado: revisado
  • Leitor de tela: revisado
  • Touch: revisado
  • Reduced motion: revisado

Dependências

Pacotes
motion
Ícones
chevron-right, file, folder, folder-open
Construído sobre
Nenhum
Usado por
Nenhum ainda