Docs

Tree Grid

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

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

Open in a
new tab
async function 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);
}

function Example() {
  return (
    <Grid itemHasChildrenPath="manager" dataProvider={dataProvider}>
      <GridTreeColumn path="firstName" />
      <GridColumn path="lastName" />
      <GridColumn path="email" />
    </Grid>
  );
}
Note
Features Shared with Grid
Tree Grid is an extension of the Grid component. Therefore, all of Grid’s features are available in Tree Grid.

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
<HorizontalLayout
  style={{ alignItems: 'center', height: 'var(--lumo-size-xl)' }}
  theme="spacing"
>
  <h3 style={{ flexGrow: 1, margin: 0 }}>Employee</h3>
  <Button onClick={expandAll}>Expand All</Button>
  <Button onClick={collapseAll}>Collapse All</Button>
</HorizontalLayout>

<Grid
  dataProvider={dataProvider}
  itemIdPath="id"
  itemHasChildrenPath="manager"
  expandedItems={expandedItems}
>
  <GridTreeColumn path="firstName" />
  <GridColumn path="lastName" />
  <GridColumn path="email" />
</Grid>

Rich Content

Like Grid, Tree Grid supports rich content.

Open in a
new tab
const [expandedItems, setExpandedItems] = useState<Person[]>([]);

return (
  <Grid dataProvider={dataProvider} expandedItems={expandedItems}>
    <GridColumn autoWidth header="Employee">
      {({ item: person, model }) => (
        <GridTreeToggle
          leaf={!person.manager}
          level={model?.level ?? 0}
          expanded={!!model?.expanded}
          onClick={(e) => {
            // The click listener needs to check if the event gets canceled (by
            // vaadin-grid-tree-toggle) and only continue if it does.
            // vaadin-grid-tree-toggle will cancel the event if the user clicks on
            // a non-focusable element inside the toggle.
            if (!e.defaultPrevented) {
              return;
            }
            if (e.currentTarget.expanded) {
              setExpandedItems([...expandedItems, person]);
            } else {
              setExpandedItems(expandedItems.filter((p) => p.id !== person.id));
            }
          }}
        >
          <HorizontalLayout style={{ alignItems: 'center' }} theme="spacing">
            <Avatar img={person.pictureUrl} name={`${person.firstName} ${person.lastName}`} />
            <VerticalLayout style={{ lineHeight: 'var(--lumo-line-height-m)' }}>
              <span>
                {person.firstName} {person.lastName}
              </span>
              <span
                style={{
                  fontSize: 'var(--lumo-font-size-s)',
                  color: 'var(--lumo-secondary-text-color)',
                }}
              >
                {person.profession}
              </span>
            </VerticalLayout>
          </HorizontalLayout>
        </GridTreeToggle>
      )}
    </GridColumn>

    <GridColumn autoWidth header="Contact">
      {({ item: person }) => (
        <VerticalLayout
          style={{
            fontSize: 'var(--lumo-font-size-s)',
            lineHeight: 'var(--lumo-line-height-m)',
          }}
        >
          <a href={`mailto:${person.email}`} style={{ display: 'flex', alignItems: 'center' }}>
            <Icon
              icon="vaadin:envelope"
              style={{
                height: 'var(--lumo-icon-size-s)',
                marginInlineEnd: 'var(--lumo-space-s)',
                width: 'var(--lumo-icon-size-s)',
              }}
            />
            <span>{person.email}</span>
          </a>
          <a
            href={`tel:${person.address.phone}`}
            style={{ display: 'flex', alignItems: 'center' }}
          >
            <Icon
              icon="vaadin:phone"
              style={{
                height: 'var(--lumo-icon-size-s)',
                marginInlineEnd: 'var(--lumo-space-s)',
                width: 'var(--lumo-icon-size-s)',
              }}
            />
            <span>{person.address.phone}</span>
          </a>
        </VerticalLayout>
      )}
    </GridColumn>
  </Grid>
);

Best Practices

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

Component Usage Recommendation

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.