Tree

Tree renders an accessible nested tree from one items prop. It keeps selection and expansion controlled independently. Clicking a branch row selects it and toggles its expansion; the chevron only toggles expansion. Start and end content can contain normal interactive controls without activating the row.

src
README.md
index.ts
package.json
import { Tree } from "density-base-ui";
import { useState } from "react";

export default function TreeExample() {
  const [expandedIds, setExpandedIds] = useState(["src"]);
  const [selectedId, setSelectedId] = useState<string>();

  return (
    <Tree
      aria-label="Project files"
      expandedIds={expandedIds}
      onExpandedIdsChange={setExpandedIds}
      selectedId={selectedId}
      onSelectedIdChange={setSelectedId}
      items={[
        {
          id: "src",
          label: "src",
          children: [
            { id: "readme", label: "README.md" },
            { id: "index", label: "index.ts" },
          ],
        },
        { id: "package", label: "package.json" },
      ]}
    />
  );
}

Child hairline

Use showChildHairline to display a subtle guide beside each nested row.

src
components
Tree.tsx
Button.tsx
index.ts
package.json
import { Tree } from "density-base-ui";
import { useState } from "react";

export default function TreeHairlineExample() {
  const [expandedIds, setExpandedIds] = useState(["src", "components"]);
  const [selectedId, setSelectedId] = useState<string>();

  return (
    <Tree
      aria-label="Nested project files"
      expandedIds={expandedIds}
      onExpandedIdsChange={setExpandedIds}
      selectedId={selectedId}
      onSelectedIdChange={setSelectedId}
      showChildHairline
      items={[
        {
          id: "src",
          label: "src",
          children: [
            {
              id: "components",
              label: "components",
              children: [
                { id: "tree", label: "Tree.tsx" },
                { id: "button", label: "Button.tsx" },
              ],
            },
            { id: "index", label: "index.ts" },
          ],
        },
        { id: "package", label: "package.json" },
      ]}
    />
  );
}

Row style

src
index.ts
docs
import { Tree } from "density-base-ui";
import { useState } from "react";

const items = [
  {
    id: "src",
    label: "src",
    children: [{ id: "index", label: "index.ts" }],
  },
  { id: "docs", label: "docs" },
];
export default function TreeRowStyleExample() {
  const [expandedIds, setExpandedIds] = useState(["src"]);
  const [selectedId, setSelectedId] = useState<string>();

  return (
    <Tree
      aria-label="Project files"
      expandedIds={expandedIds}
      onExpandedIdsChange={setExpandedIds}
      selectedId={selectedId}
      onSelectedIdChange={setSelectedId}
      items={items}
      rowStyle={{ paddingBlock: "0.25rem" }}
    />
  );
}

Size

2xs
Child
xs
Child
sm
Child
md
Child
lg
Child
xl
Child
2xl
Child
3xl
Child
import { Tree, type TreeRowSize, View } from "density-base-ui";
import { useState } from "react";

const getTreeItems = (id: string) => [
  { id, label: id, children: [{ id: `${id}-child`, label: "Child" }] },
];

function InteractiveTreeSizeExample({ size }: { size: TreeRowSize }) {
  const [expandedIds, setExpandedIds] = useState<string[]>([size]);
  const [selectedId, setSelectedId] = useState<string>();

  return (
    <Tree
      aria-label={`${size} tree`}
      size={size}
      expandedIds={expandedIds}
      onExpandedIdsChange={setExpandedIds}
      selectedId={selectedId}
      onSelectedIdChange={setSelectedId}
      items={getTreeItems(size)}
    />
  );
}

export default function TreeSizeExample() {
  return (
    <View>
      <InteractiveTreeSizeExample size="2xs" />
      <InteractiveTreeSizeExample size="xs" />
      <InteractiveTreeSizeExample size="sm" />
      <InteractiveTreeSizeExample size="md" />
      <InteractiveTreeSizeExample size="lg" />
      <InteractiveTreeSizeExample size="xl" />
      <InteractiveTreeSizeExample size="2xl" />
      <InteractiveTreeSizeExample size="3xl" />
    </View>
  );
}