Search

Search the site

All components

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
1"use client";
2
3import { useState } from "react";
4import { FileTree, type FileTreeNode } from "@/registry/ui";
5
6const 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];
95
96export function FileTreeDefault() {
97 const [selectedPath, setSelectedPath] = useState<string>("");
98
99 const handleSelect = (node: FileTreeNode, path: string) => {
100 setSelectedPath(path);
101 };
102
103 return (
104 <div>
105 <FileTree
106 data={sampleData}
107 variant="default"
108 size="default"
109 onSelect={handleSelect}
110 selectedPath={selectedPath}
111 />
112 </div>
113 );
114}
Bordered
Bordered file tree
package.json
tsconfig.json
next.config.mjs
tailwind.config.ts
.env.local
.gitignore
README.md
1"use client";
2
3import { useState } from "react";
4import { FileTree, type FileTreeNode } from "@/registry/ui";
5
6const 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];
95
96export function FileTreeBordered() {
97 const [selectedPath, setSelectedPath] = useState<string>("");
98
99 const handleSelect = (node: FileTreeNode, path: string) => {
100 setSelectedPath(path);
101 };
102
103 return (
104 <div>
105 <FileTree
106 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
package.json
tsconfig.json
next.config.mjs
tailwind.config.ts
.env.local
.gitignore
README.md
1"use client";
2
3import { useState } from "react";
4import { FileTree, type FileTreeNode } from "@/registry/ui";
5
6const 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];
95
96export function FileTreeElevated() {
97 const [selectedPath, setSelectedPath] = useState<string>("");
98
99 const handleSelect = (node: FileTreeNode, path: string) => {
100 setSelectedPath(path);
101 };
102
103 return (
104 <div>
105 <FileTree
106 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
package.json
tsconfig.json
next.config.mjs
tailwind.config.ts
.env.local
.gitignore
README.md
1"use client";
2
3import { useState } from "react";
4import { FileTree, type FileTreeNode } from "@/registry/ui";
5
6const 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];
95
96export function FileTreeGhost() {
97 const [selectedPath, setSelectedPath] = useState<string>("");
98
99 const handleSelect = (node: FileTreeNode, path: string) => {
100 setSelectedPath(path);
101 };
102
103 return (
104 <div>
105 <FileTree
106 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

NameTypeDefaultDescription
dataFileTreeNode[][]The data to display in the file tree
variant"default" | "ghost" | "bordered" | "elevated"defaultThe variant of the file tree
size"sm" | "default" | "lg"defaultThe size of the file tree
defaultExpandedbooleantrueWhether the file tree is expanded by default
onSelect() => voidundefinedCallback when a file or folder is selected
selectedPathstringundefinedThe selected path in the file tree
onExpand() => voidundefinedCallback when a file or folder is expanded
onCollapse() => voidundefinedCallback when a file or folder is collapsed