File Tree
Hierarchical file tree with folder expand/collapse. Pair with FileExplorer + FileViewer for a collapsible explorer panel (sidebar hide/show is on FileExplorer, not FileTree).
Default
Default file tree
src
app
layout.tsx
page.tsx
globals.css
api
auth
route.ts
users
route.ts
components
ui
button.tsx
card.tsx
file-tree.tsx
header.tsx
footer.tsx
lib
utils.ts
constants.ts
hooks
use-auth.ts
use-theme.ts
public
favicon.ico
logo.svg
images
hero.png
avatar.jpg
package.json
tsconfig.json
next.config.mjs
tailwind.config.ts
.env.local
.gitignore
README.md
default-example.tsx
1"use client";23import { useState } from "react";4import { FileTree, type FileTreeNode } from "@/registry/ui";56const sampleData: FileTreeNode[] = [7 {8 name: "src",9 type: "folder",10 children: [11 {12 name: "app",13 type: "folder",14 children: [15 { name: "layout.tsx", type: "file" },16 { name: "page.tsx", type: "file" },17 { name: "globals.css", type: "file" },18 {19 name: "api",20 type: "folder",21 children: [22 {23 name: "auth",24 type: "folder",25 children: [{ name: "route.ts", type: "file" }],26 },27 {28 name: "users",29 type: "folder",30 children: [{ name: "route.ts", type: "file" }],31 },32 ],33 },34 ],35 },36 {37 name: "components",38 type: "folder",39 children: [40 {41 name: "ui",42 type: "folder",43 children: [44 { name: "button.tsx", type: "file" },45 { name: "card.tsx", type: "file" },46 { name: "file-tree.tsx", type: "file" },47 ],48 },49 { name: "header.tsx", type: "file" },50 { name: "footer.tsx", type: "file" },51 ],52 },53 {54 name: "lib",55 type: "folder",56 children: [57 { name: "utils.ts", type: "file" },58 { name: "constants.ts", type: "file" },59 ],60 },61 {62 name: "hooks",63 type: "folder",64 children: [65 { name: "use-auth.ts", type: "file" },66 { name: "use-theme.ts", type: "file" },67 ],68 },69 ],70 },71 {72 name: "public",73 type: "folder",74 children: [75 { name: "favicon.ico", type: "file" },76 { name: "logo.svg", type: "file" },77 {78 name: "images",79 type: "folder",80 children: [81 { name: "hero.png", type: "file" },82 { name: "avatar.jpg", type: "file" },83 ],84 },85 ],86 },87 { name: "package.json", type: "file" },88 { name: "tsconfig.json", type: "file" },89 { name: "next.config.mjs", type: "file" },90 { name: "tailwind.config.ts", type: "file" },91 { name: ".env.local", type: "file" },92 { name: ".gitignore", type: "file" },93 { name: "README.md", type: "file" },94];9596export function FileTreeDefault() {97 const [selectedPath, setSelectedPath] = useState<string>("");9899 const handleSelect = (node: FileTreeNode, path: string) => {100 setSelectedPath(path);101 };102103 return (104 <div>105 <FileTree106 data={sampleData}107 variant="default"108 size="default"109 onSelect={handleSelect}110 selectedPath={selectedPath}111 />112 </div>113 );114}
Bordered
Bordered file tree
src
public
package.json
tsconfig.json
next.config.mjs
tailwind.config.ts
.env.local
.gitignore
README.md
bordered-example.tsx
1"use client";23import { useState } from "react";4import { FileTree, type FileTreeNode } from "@/registry/ui";56const sampleData: FileTreeNode[] = [7 {8 name: "src",9 type: "folder",10 children: [11 {12 name: "app",13 type: "folder",14 children: [15 { name: "layout.tsx", type: "file" },16 { name: "page.tsx", type: "file" },17 { name: "globals.css", type: "file" },18 {19 name: "api",20 type: "folder",21 children: [22 {23 name: "auth",24 type: "folder",25 children: [{ name: "route.ts", type: "file" }],26 },27 {28 name: "users",29 type: "folder",30 children: [{ name: "route.ts", type: "file" }],31 },32 ],33 },34 ],35 },36 {37 name: "components",38 type: "folder",39 children: [40 {41 name: "ui",42 type: "folder",43 children: [44 { name: "button.tsx", type: "file" },45 { name: "card.tsx", type: "file" },46 { name: "file-tree.tsx", type: "file" },47 ],48 },49 { name: "header.tsx", type: "file" },50 { name: "footer.tsx", type: "file" },51 ],52 },53 {54 name: "lib",55 type: "folder",56 children: [57 { name: "utils.ts", type: "file" },58 { name: "constants.ts", type: "file" },59 ],60 },61 {62 name: "hooks",63 type: "folder",64 children: [65 { name: "use-auth.ts", type: "file" },66 { name: "use-theme.ts", type: "file" },67 ],68 },69 ],70 },71 {72 name: "public",73 type: "folder",74 children: [75 { name: "favicon.ico", type: "file" },76 { name: "logo.svg", type: "file" },77 {78 name: "images",79 type: "folder",80 children: [81 { name: "hero.png", type: "file" },82 { name: "avatar.jpg", type: "file" },83 ],84 },85 ],86 },87 { name: "package.json", type: "file" },88 { name: "tsconfig.json", type: "file" },89 { name: "next.config.mjs", type: "file" },90 { name: "tailwind.config.ts", type: "file" },91 { name: ".env.local", type: "file" },92 { name: ".gitignore", type: "file" },93 { name: "README.md", type: "file" },94];9596export function FileTreeBordered() {97 const [selectedPath, setSelectedPath] = useState<string>("");9899 const handleSelect = (node: FileTreeNode, path: string) => {100 setSelectedPath(path);101 };102103 return (104 <div>105 <FileTree106 data={sampleData}107 variant="bordered"108 size="default"109 defaultExpanded={false}110 onSelect={handleSelect}111 selectedPath={selectedPath}112 />113 </div>114 );115}
Elevated
Elevated file tree
src
public
package.json
tsconfig.json
next.config.mjs
tailwind.config.ts
.env.local
.gitignore
README.md
elevated-example.tsx
1"use client";23import { useState } from "react";4import { FileTree, type FileTreeNode } from "@/registry/ui";56const sampleData: FileTreeNode[] = [7 {8 name: "src",9 type: "folder",10 children: [11 {12 name: "app",13 type: "folder",14 children: [15 { name: "layout.tsx", type: "file" },16 { name: "page.tsx", type: "file" },17 { name: "globals.css", type: "file" },18 {19 name: "api",20 type: "folder",21 children: [22 {23 name: "auth",24 type: "folder",25 children: [{ name: "route.ts", type: "file" }],26 },27 {28 name: "users",29 type: "folder",30 children: [{ name: "route.ts", type: "file" }],31 },32 ],33 },34 ],35 },36 {37 name: "components",38 type: "folder",39 children: [40 {41 name: "ui",42 type: "folder",43 children: [44 { name: "button.tsx", type: "file" },45 { name: "card.tsx", type: "file" },46 { name: "file-tree.tsx", type: "file" },47 ],48 },49 { name: "header.tsx", type: "file" },50 { name: "footer.tsx", type: "file" },51 ],52 },53 {54 name: "lib",55 type: "folder",56 children: [57 { name: "utils.ts", type: "file" },58 { name: "constants.ts", type: "file" },59 ],60 },61 {62 name: "hooks",63 type: "folder",64 children: [65 { name: "use-auth.ts", type: "file" },66 { name: "use-theme.ts", type: "file" },67 ],68 },69 ],70 },71 {72 name: "public",73 type: "folder",74 children: [75 { name: "favicon.ico", type: "file" },76 { name: "logo.svg", type: "file" },77 {78 name: "images",79 type: "folder",80 children: [81 { name: "hero.png", type: "file" },82 { name: "avatar.jpg", type: "file" },83 ],84 },85 ],86 },87 { name: "package.json", type: "file" },88 { name: "tsconfig.json", type: "file" },89 { name: "next.config.mjs", type: "file" },90 { name: "tailwind.config.ts", type: "file" },91 { name: ".env.local", type: "file" },92 { name: ".gitignore", type: "file" },93 { name: "README.md", type: "file" },94];9596export function FileTreeElevated() {97 const [selectedPath, setSelectedPath] = useState<string>("");9899 const handleSelect = (node: FileTreeNode, path: string) => {100 setSelectedPath(path);101 };102103 return (104 <div>105 <FileTree106 data={sampleData}107 variant="elevated"108 size="sm"109 defaultExpanded={false}110 onSelect={handleSelect}111 selectedPath={selectedPath}112 />113 </div>114 );115}
Ghost + Large Size
Ghost file tree with large size
src
public
package.json
tsconfig.json
next.config.mjs
tailwind.config.ts
.env.local
.gitignore
README.md
ghost-example.tsx
1"use client";23import { useState } from "react";4import { FileTree, type FileTreeNode } from "@/registry/ui";56const sampleData: FileTreeNode[] = [7 {8 name: "src",9 type: "folder",10 children: [11 {12 name: "app",13 type: "folder",14 children: [15 { name: "layout.tsx", type: "file" },16 { name: "page.tsx", type: "file" },17 { name: "globals.css", type: "file" },18 {19 name: "api",20 type: "folder",21 children: [22 {23 name: "auth",24 type: "folder",25 children: [{ name: "route.ts", type: "file" }],26 },27 {28 name: "users",29 type: "folder",30 children: [{ name: "route.ts", type: "file" }],31 },32 ],33 },34 ],35 },36 {37 name: "components",38 type: "folder",39 children: [40 {41 name: "ui",42 type: "folder",43 children: [44 { name: "button.tsx", type: "file" },45 { name: "card.tsx", type: "file" },46 { name: "file-tree.tsx", type: "file" },47 ],48 },49 { name: "header.tsx", type: "file" },50 { name: "footer.tsx", type: "file" },51 ],52 },53 {54 name: "lib",55 type: "folder",56 children: [57 { name: "utils.ts", type: "file" },58 { name: "constants.ts", type: "file" },59 ],60 },61 {62 name: "hooks",63 type: "folder",64 children: [65 { name: "use-auth.ts", type: "file" },66 { name: "use-theme.ts", type: "file" },67 ],68 },69 ],70 },71 {72 name: "public",73 type: "folder",74 children: [75 { name: "favicon.ico", type: "file" },76 { name: "logo.svg", type: "file" },77 {78 name: "images",79 type: "folder",80 children: [81 { name: "hero.png", type: "file" },82 { name: "avatar.jpg", type: "file" },83 ],84 },85 ],86 },87 { name: "package.json", type: "file" },88 { name: "tsconfig.json", type: "file" },89 { name: "next.config.mjs", type: "file" },90 { name: "tailwind.config.ts", type: "file" },91 { name: ".env.local", type: "file" },92 { name: ".gitignore", type: "file" },93 { name: "README.md", type: "file" },94];9596export function FileTreeGhost() {97 const [selectedPath, setSelectedPath] = useState<string>("");9899 const handleSelect = (node: FileTreeNode, path: string) => {100 setSelectedPath(path);101 };102103 return (104 <div>105 <FileTree106 data={sampleData}107 variant="ghost"108 size="lg"109 defaultExpanded={false}110 onSelect={handleSelect}111 selectedPath={selectedPath}112 />113 </div>114 );115}
Installation & source
Install via the shadcn CLI or copy the registry files manually.
bash
npx shadcn@latest add @tt-ui/file-tree
Props
| Name | Type | Default | Description |
|---|---|---|---|
| data | FileTreeNode[] | [] | The data to display in the file tree |
| variant | "default" | "ghost" | "bordered" | "elevated" | default | The variant of the file tree |
| size | "sm" | "default" | "lg" | default | The size of the file tree |
| defaultExpanded | boolean | true | Whether the file tree is expanded by default |
| onSelect | () => void | undefined | Callback when a file or folder is selected |
| selectedPath | string | undefined | The selected path in the file tree |
| onExpand | () => void | undefined | Callback when a file or folder is expanded |
| onCollapse | () => void | undefined | Callback when a file or folder is collapsed |