Preview Updated 2026-05-10

Tree view

Nested tree display with single-select / checkbox (with cascading), expand / collapse, and custom icons.

Basic usage

nodes is a tree (each node may have children). selectedKey + update:selectedKey controls the single-select highlight; defaultExpandedKeys sets initially expanded node keys. disabled nodes don’t respond to clicks.

背景
  • src
    • components
      • Home.vue
      • About.vue
      • Contact.vue
    • main.ts
    • styles.css
  • README.md
<script setup lang="ts">
import { ref } from 'vue';
import { CfTreeView, type TreeNode } from '@chufix-design/vue';

const selected = ref<string | null>('home');

const nodes: TreeNode[] = [
  {
    key: 'src',
    label: 'src',
    children: [
      {
        key: 'components',
        label: 'components',
        children: [
          { key: 'home', label: 'Home.vue' },
          { key: 'about', label: 'About.vue' },
          { key: 'contact', label: 'Contact.vue', disabled: true },
        ],
      },
      { key: 'main', label: 'main.ts' },
      { key: 'styles', label: 'styles.css' },
    ],
  },
  { key: 'readme', label: 'README.md' },
];
</script>

<template>
  <div style="border: 1px solid var(--line-1); border-radius: 8px; padding: 8px; max-width: 18rem;">
    <CfTreeView
      :nodes="nodes"
      :selected-key="selected"
      :default-expanded-keys="['src', 'components']"
      @update:selected-key="selected = $event"
    />
  </div>
</template>
import { useState } from 'react';
import { CfTreeView, type TreeNode } from '@chufix-design/react';

const nodes: TreeNode[] = [/* ... */];

export default function Demo() {
const [selected, setSelected] = useState<string | null>('home');
return (
  <CfTreeView
    nodes={nodes}
    selectedKey={selected}
    defaultExpandedKeys={['src', 'components']}
    onSelectedKeyChange={setSelected}
  />
);
}

Checkbox with cascading

checkable adds a checkbox to each node, paired with v-model (Vue) / value + onChange (React) bound to string[]. cascade=true (default) makes parent / child checks affect each other — checking a parent checks all descendants, and checking all descendants checks the parent; half-checked state becomes indeterminate automatically.

With cascade=false, each node is independent, useful for industry / tag multi-select cases.

背景
cascade = true(默认)
  • src
    • components
      • Home.vue
      • About.vue
    • main.ts
    • styles.css
  • README.md
cascade = false
  • src
    • components
      • Home.vue
      • About.vue
    • main.ts
    • styles.css
  • README.md
<script setup lang="ts">
import { ref } from 'vue';
import { CfTreeView, type TreeNode } from '@chufix-design/vue';

const checked = ref<string[]>(['styles']);

const nodes: TreeNode[] = [
  {
    key: 'src',
    label: 'src',
    children: [
      {
        key: 'components',
        label: 'components',
        children: [
          { key: 'home', label: 'Home.vue' },
          { key: 'about', label: 'About.vue' },
        ],
      },
      { key: 'main', label: 'main.ts' },
      { key: 'styles', label: 'styles.css' },
    ],
  },
  { key: 'readme', label: 'README.md' },
];
</script>

<template>
  <div style="display:grid; grid-template-columns: 1fr 1fr; gap: 16px;">
    <div style="border: 1px solid var(--line-1); border-radius: 8px; padding: 8px;">
      <div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">cascade = true(默认)</div>
      <CfTreeView
        v-model="checked"
        :nodes="nodes"
        checkable
        :default-expanded-keys="['src', 'components']"
      />
    </div>
    <div style="border: 1px solid var(--line-1); border-radius: 8px; padding: 8px;">
      <div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">cascade = false</div>
      <CfTreeView
        v-model="checked"
        :nodes="nodes"
        checkable
        :cascade="false"
        :default-expanded-keys="['src', 'components']"
      />
    </div>
  </div>
</template>
<CfTreeView nodes={nodes} value={checked} onChange={setChecked} checkable />

{/* Cascading off */}
<CfTreeView nodes={nodes} value={checked} onChange={setChecked} checkable cascade={false} />

Sizes

size controls node row height and font size — sm compact (common in sidebar file trees) / md default / lg for touch-friendly use.

背景
size = sm
  • src
    • main.ts
    • App.vue
  • package.json
size = md
  • src
    • main.ts
    • App.vue
  • package.json
size = lg
  • src
    • main.ts
    • App.vue
  • package.json
<script setup lang="ts">
import { ref } from 'vue';
import { CfTreeView, type TreeNode } from '@chufix-design/vue';

const a = ref<string | null>('main');
const b = ref<string | null>('main');
const c = ref<string | null>('main');

const nodes: TreeNode[] = [
  {
    key: 'src',
    label: 'src',
    children: [
      { key: 'main', label: 'main.ts' },
      { key: 'app', label: 'App.vue' },
    ],
  },
  { key: 'package', label: 'package.json' },
];
</script>

<template>
  <div style="display:grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px;">
    <div style="border: 1px solid var(--line-1); border-radius: 8px; padding: 8px;">
      <div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">size = sm</div>
      <CfTreeView size="sm" :nodes="nodes" :selected-key="a" :default-expanded-keys="['src']" @update:selected-key="a = $event" />
    </div>
    <div style="border: 1px solid var(--line-1); border-radius: 8px; padding: 8px;">
      <div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">size = md</div>
      <CfTreeView size="md" :nodes="nodes" :selected-key="b" :default-expanded-keys="['src']" @update:selected-key="b = $event" />
    </div>
    <div style="border: 1px solid var(--line-1); border-radius: 8px; padding: 8px;">
      <div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">size = lg</div>
      <CfTreeView size="lg" :nodes="nodes" :selected-key="c" :default-expanded-keys="['src']" @update:selected-key="c = $event" />
    </div>
  </div>
</template>
<CfTreeView size="sm" nodes={nodes} />
<CfTreeView size="md" nodes={nodes} />
<CfTreeView size="lg" nodes={nodes} />

Hide connector lines

showLine={false} hides the dashed parent-child connectors — cleaner look, often paired with custom icons.

背景
  • src
    • components
      • Home.vue
      • About.vue
    • main.ts
<script setup lang="ts">
import { ref } from 'vue';
import { CfTreeView, type TreeNode } from '@chufix-design/vue';

const selected = ref<string | null>('home');

const nodes: TreeNode[] = [
  {
    key: 'src',
    label: 'src',
    children: [
      {
        key: 'components',
        label: 'components',
        children: [
          { key: 'home', label: 'Home.vue' },
          { key: 'about', label: 'About.vue' },
        ],
      },
      { key: 'main', label: 'main.ts' },
    ],
  },
];
</script>

<template>
  <div style="border: 1px solid var(--line-1); border-radius: 8px; padding: 8px; max-width: 18rem;">
    <CfTreeView
      :nodes="nodes"
      :selected-key="selected"
      :default-expanded-keys="['src', 'components']"
      :show-line="false"
      @update:selected-key="selected = $event"
    />
  </div>
</template>
<CfTreeView nodes={nodes} showLine={false} />

API

PropTypeDefaultDescription
nodesTreeNode[][]Tree data
modelValue (Vue) / value (React)string[][]Checked keys (checkable mode only)
expandedKeys / defaultExpandedKeysstring[]Controlled / uncontrolled expanded list
selectedKeystring | nullnullCurrently selected key
checkablebooleanfalseShow checkboxes
cascadebooleantrueCascading parent / child checks
size'sm' | 'md' | 'lg''md'Font size + padding
showLinebooleantrueShow nested connector lines
emptyTextstring | ReactNode'No data'Empty state text

TreeNode:

interface TreeNode {
  key: string;
  label: string;
  icon?: VNode | ReactNode;
  children?: TreeNode[];
  disabled?: boolean;
  selectable?: boolean;
  isLeaf?: boolean;
}

Events: update:modelValue / update:expandedKeys / update:selectedKey / select / expand / check (React: onChange / onExpandedKeysChange / onSelectedKeyChange / onSelect / onExpand / onCheck).

反馈与讨论

Tree view · Discussion

0
0 / 600
一键发送
正在加载评论...