Documentation

Documentation versions (currently viewingVaadin 23)

You are viewing documentation for Vaadin 23. View latest documentation

Tree Grid

Tree Grid is a component for displaying hierarchical tabular data grouped into expandable and collapsible nodes.

Open in a
new tab
async dataProvider(
  params: GridDataProviderParams<Person>,
  callback: GridDataProviderCallback<Person>
) {
  // The requested page and the full length of the corresponding
  // hierarchy level is requested from the data service
  const { people, hierarchyLevelSize } = await getPeople({
    count: params.pageSize,
    startIndex: params.page * params.pageSize,
    managerId: params.parentItem ? params.parentItem.id : null,
  });

  callback(people, hierarchyLevelSize);
}

protected override render() {
  return html`
    <vaadin-grid .dataProvider="${this.dataProvider}">
      <vaadin-grid-tree-column
        path="firstName"
        item-has-children-path="manager"
      ></vaadin-grid-tree-column>
      <vaadin-grid-column path="lastName"></vaadin-grid-column>
      <vaadin-grid-column path="email"></vaadin-grid-column>
    </vaadin-grid>
  `;
}
Note
Features shared with Grid
Tree Grid is an extension of the Grid component and all Grid’s features are available in Tree Grid as well.

Tree Column

The tree column is a column that contains the toggles for expanding and collapsing nodes. Nodes are opened and closed by clicking a tree column’s cell. They can also be toggled programmatically.

Open in a
new tab
@state()
private expandedItems: unknown[] = [];

protected override render() {
  return html`
    <vaadin-horizontal-layout
      style="align-items: center; height: var(--lumo-size-xl);"
      theme="spacing"
    >
      <h3 style="flex-grow: 1; margin: 0;">Employee</h3>
      <vaadin-button @click="${this.expandAll}">Expand All</vaadin-button>
      <vaadin-button @click="${this.collapseAll}">Collapse All</vaadin-button>
    </vaadin-horizontal-layout>

    <vaadin-grid
      .dataProvider="${this.dataProvider}"
      .itemIdPath="${'id'}"
      .expandedItems="${this.expandedItems}"
    >
      <vaadin-grid-tree-column
        path="firstName"
        item-has-children-path="manager"
      ></vaadin-grid-tree-column>
      <vaadin-grid-column path="lastName"></vaadin-grid-column>
      <vaadin-grid-column path="email"></vaadin-grid-column>
    </vaadin-grid>
  `;
}

private expandAll() {
  this.expandedItems = [...this.managers];
}

private collapseAll() {
  this.expandedItems = [];
}

Rich Content

Like Grid, Tree Grid supports rich content.

Open in a
new tab
private employeeRenderer: GridColumnBodyLitRenderer<Person> = (person, model) => html`
  <vaadin-grid-tree-toggle
    .leaf="${!person.manager}"
    .level="${model.level ?? 0}"
    @expanded-changed="${(e: GridTreeToggleExpandedChangedEvent) => {
      if (e.detail.value) {
        this.expandedItems = [...this.expandedItems, person];
      } else {
        this.expandedItems = this.expandedItems.filter((p) => p.id !== person.id);
      }
    }}"
    .expanded="${!!model.expanded}"
  >
    <vaadin-horizontal-layout style="align-items: center;" theme="spacing">
      <vaadin-avatar
        img="${person.pictureUrl}"
        name="${`${person.firstName} ${person.lastName}`}"
      ></vaadin-avatar>
      <vaadin-vertical-layout style="line-height: var(--lumo-line-height-m);">
        <span>${person.firstName} ${person.lastName}</span>
        <span
          style="font-size: var(--lumo-font-size-s); color: var(--lumo-secondary-text-color);"
        >
          ${person.profession}
        </span>
      </vaadin-vertical-layout>
    </vaadin-horizontal-layout>
  </vaadin-grid-tree-toggle>
`;

private contactRenderer: GridColumnBodyLitRenderer<Person> = (person) => html`
  <vaadin-vertical-layout
    style="font-size: var(--lumo-font-size-s); line-height: var(--lumo-line-height-m);"
  >
    <a href="mailto:${person.email}" style="align-items: center; display: flex;">
      <vaadin-icon
        icon="vaadin:envelope"
        style="height: var(--lumo-icon-size-s); margin-inline-end: var(--lumo-space-s); width: var(--lumo-icon-size-s);"
      ></vaadin-icon>
      <span>${person.email}</span>
    </a>
    <a href="tel:${person.address.phone}" style="align-items: center; display: flex;">
      <vaadin-icon
        icon="vaadin:phone"
        style="height: var(--lumo-icon-size-s); margin-inline-end: var(--lumo-space-s); width: var(--lumo-icon-size-s);"
      ></vaadin-icon>
      <span>${person.address.phone}</span>
    </a>
  </vaadin-vertical-layout>
`;

protected override render() {
  return html`
    <vaadin-grid .dataProvider="${this.dataProvider}" .expandedItems="${this.expandedItems}">
      <vaadin-grid-column
        auto-width
        header="Employee"
        ${columnBodyRenderer(this.employeeRenderer, [])}
      ></vaadin-grid-column>
      <vaadin-grid-column
        auto-width
        header="Contact"
        ${columnBodyRenderer(this.contactRenderer, [])}
      ></vaadin-grid-column>
    </vaadin-grid>
  `;
}

Best Practices

Tree Grid isn’t meant to be used as a navigation menu.

Caution
scrollToIndex() isn’t reliable
The behavior of the scrollToIndex() method in Tree Grid isn’t deterministic due to lazy-loading hierarchical data. It isn’t recommended to use this method.
Component Usage Recommendations

Grid

Component for showing tabular data.

Grid Pro

Component for showing and editing tabular data.

CRUD

Component for creating, displaying, updating and deleting tabular data.

9DEF736F-975A-469A-8625-A0A6E086BF50