1771 Technologies Logo

Columns

Column Grouping

Column Grouping allows you to specify hierarchical relationships among columns. The groupId property specifies the column group a particular column belongs to.

When specifying column groups, a tree structure is defined for the grouping, and the groupId specifies the path of the column within that tree. Graphite Grid maintains a flat representation of columns, with each individual column declaratively describing which column group it is a part of.

Individual columns are part of the same group when they have the same value for the groupId property, even if the columns are not contiguous in the definitions. This means they will share the same collapse state across the grid. In the example below, notice that collapsing any of the "Greeks" grouping collapses both groups.

export function ColumnGroups() {
  const grid = useGraphiteGrid({
    initial: {
      columnDefinitions: [
        { id: "Alpha", groupId: ["Greeks"], field: 0 },
        { id: "Beta", groupId: ["Greeks"], field: 1 },
        { id: "Stock Price", field: 2 },
        { id: "Gamma", groupId: ["Greeks"], field: 3 },
        { id: "Nested", groupId: ["Nested", "Level 2"], field: 3 },
      ],
      // other grid properties
    },
  });
 
  return (
    <div style={{ height: 400 }}>
      <GraphiteGridDom state={grid} />
    </div>
  );
}

Column Group Visibility

Graphite Grid determines if a column group can be expanded or collapsed depending on the value of the groupVisibility property of all the columns in the column group. The groupVisibility property is defined on individual columns and may take one of the following values:

  • "always-visible"
  • "visible-when-closed"
  • "visible-when-open"

A column group may not be collapsed when all the columns in that group have a groupVisibility value of "always-visible". The default value for columns is "visible-when-open".

export function ColumnGroupsAlwaysVisible() {
  const grid = useGraphiteGrid({
    initial: {
      columnDefinitions: [
        { id: "Alpha", groupId: ["Greeks"], field: 0 },
        { id: "Beta", groupId: ["Greeks"], field: 1 },
        { id: "Stock Price", field: 2 },
        {
          id: "Gamma",
          groupId: ["Greeks"],
          field: 3,
          groupVisibility: "always-visible",
        },
        {
          id: "Epsilon",
          groupId: ["Greeks"],
          field: 3,
          groupVisibility: "always-visible",
        },
      ],
      // other grid properties
    },
  });
 
  return (
    <div style={{ height: 400 }}>
      <GraphiteGridDom state={grid} />
    </div>
  );
}

In the above example, notice that the first column group is collapsible, but the second group cannot be collapsed because all the members have a groupVisibility value of "always-visible".

Collapsed Column Group Visibility

Two outcomes may occur when a column group is collapsed depending on the value of the groupVisibility for the individual columns that make up that group:

  • If one or more columns have "always-visible" or "visible-when-closed" set, collapsing a group will result in hiding columns not visible when the group is closed.
  • If all the columns have visible-when-open (which is the default), then collapsing the group replaces the column with an empty collapsed state column, which may be expanded to open the group.
export function CollapsedVisibility() {
  const grid = useGraphiteGrid({
    initial: {
      columnDefinitions: [
        { id: "Alpha", groupId: ["Greeks"], field: 0 },
        {
          id: "Beta",
          groupId: ["Greeks"],
          field: 1,
          groupVisibility: "visible-when-closed",
        },
        { id: "Stock Price", field: 2 },
        { id: "Gamma", groupId: ["Hidden On Collapse"], field: 3 },
        { id: "Epsilon", groupId: ["Hidden On Collapse"], field: 3 },
      ],
      // other grid properties
    },
  });
 
  return (
    <div style={{ height: 400 }}>
      <GraphiteGridDom state={grid} />
    </div>
  );
}

In the above example, the Beta column is only visible when the group it is a part of is collapsed. However, the Gamma and Epsilon columns are hidden when the group is collapsed, resulting in the collapsed column being rendered.

Column ID Path Delimiter

Column groups are specified as an array of strings on the column definition. This array of strings is subsequently joined using a delimiter to create a group ID for the column group. Graphite Grid uses a default delimiter to join the group IDs. This default can be changed by specifying a value for the columnIdPathDelimiter in the initial state. This value cannot be changed once set.

const grid = useGraphiteGrid({
  initial: {
    columnIdPathDelimiter: "--",
    // other grid properties
  },
});

Given the above settings, a group such as ["A", "B", "C"] has an ID of "A--B--C".

Column Group Header Renderer

To override what is displayed in a column group cell, use the columnHeaderGroupRenderer property on the grid. In the example below, a custom renderer styles the cell with Tailwind.

export function ColumnGroupRenderer() {
  const grid = useGraphiteGrid({
    initial: {
      columnHeaderGroupRenderer: ({ columnGroup }) => {
        return (
          <div className="flex items-center justify-center bg-red-200 dark:bg-red-400 h-full">
            {columnGroup.occurrenceKey}
          </div>
        );
      },
      // other grid properties
    },
  });
 
  return (
    <div style={{ height: 400 }}>
      <GraphiteGridDom state={grid} />
    </div>
  );
}

Notice that the expansion indicator does not match the new renderer's style. The expansion renderer is a separate component from the column group renderer, which can be changed using the columnHeaderGroupExpansionRenderer property.

Info

The code example uses the columnGroup.occurrenceKey value for the group's contents. The occurrenceKey is the column group's ID plus a position count. Since the same column group may be split across the Grid, each occurrence is given an incremented count.

export function ColumnGroupRendererExpansion() {
  const grid = useGraphiteGrid({
    initial: {
      columnHeaderGroupExpansionRenderer: ({ api, groupId }) => {
        const isExpanded = api.useApiSlice((s) => s.isColumnGroupExpanded(groupId));
 
        return (
          <button
            className="flex items-center justify-center bg-red-200 dark:bg-red-400 h-full w-8"
            onClick={() => api.toggleColumnGroup(groupId)}
          >
            {isExpanded ? "-" : "+"}
          </button>
        );
      },
      // other grid properties
    },
  });
  // ...
}

The expansion renderer is styled in the code above to match the group renderer. The api.useApiSlice method lets a component reactively listen to grid changes, and the isColumnGroupExpanded(groupId) call returns true if the column group is expanded.

Resizing Column Groups

A column group can be used to simultaneously resize the individual columns within the group. A column group will only be resizable if all the columns in the group are resizable. In this case the change in size is distributed among the columns in the group. The resizable property on the definition must be true for a column to be resizable.

export function ColumnGroupResizing() {
  const grid = useGraphiteGrid({
    initial: {
      columnDefinitions: [
        {
          id: "Alpha",
          groupId: ["Parent", "Resizable"],
          resizable: true,
          field: 0,
        },
        {
          id: "Beta",
          groupId: ["Parent", "Resizable"],
          resizable: true,
          field: 1,
        },
        { id: "Gamma", groupId: ["Parent", "Not Resizable"], field: 2 },
        { id: "Epsilon", groupId: ["Parent", "Not Resizable"], field: 3 },
      ],
      // other grid properties
    },
  });
 
  return (
    <div style={{ height: 400 }}>
      <GraphiteGridDom state={grid} />
    </div>
  );
}

The Resizable column group can be used to resize the Alpha and Beta columns because both columns are resizable. The Parent and Not Resizable column groups cannot be resized as the Gamma and Epsilon columns are not resizable.

Tip

A column can be resized by hovering over the column with your pointer and dragging the resize handle (Note: The resize handle is a colored bar on the edge of the column).

Moving Column Groups

A column group can be used to move columns in bulk. A column group will only be moveable if all the columns in the group are moveable.

export function ColumnGroupMoveable() {
  const grid = useGraphiteGrid({
    initial: {
      columnDefinitions: [
        {
          id: "Alpha",
          groupId: ["Parent", "Moveable"],
          moveable: true,
          field: 0,
        },
        {
          id: "Beta",
          groupId: ["Parent", "Moveable"],
          moveable: true,
          field: 1,
        },
        { id: "Gamma", groupId: ["Parent", "Not Moveable"], field: 2 },
        { id: "Epsilon", groupId: ["Parent", "Not Moveable"], field: 3 },
      ],
      // other grid properties
    },
  });
 
  return (
    <div style={{ height: 400 }}>
      <GraphiteGridDom state={grid} />
    </div>
  );
}

The Moveable group can be moved to a new position as the Alpha and Beta columns are moveable. The Parent and Not Moveable groups are not moveable, as the Gamma and Epsilon columns are not moveable. Moving a column group within itself has no effect.

Tip

Column groups can be moved by clicking and dragging the header cell. If the resize handle is clicked, it takes precedence over the move.

Sticky Label

Column groups span many columns. The grid may be scrolled horizontally when columns take more horizontal space than the viewport. The label of the column group may be hidden as the user scrolls. To avoid this, set the stickyHeaderLabel value to true (this value applies to both columns and column groups).

export function ColumnGroupStickyLabel() {
  const grid = useGraphiteGrid({
    initial: {
      stickyHeaderLabel: true,
      // other grid properties
    },
  });
  // ...
}

Column Group Header Height

The height of the column group header may be controlled using the columnHeaderGroupHeight property on the grid. This value can be "auto" or a number representing height in px. Using a fixed height is generally recommended as the "auto" can cause layout shifts if the content of column group headers changes.

export function ColumnGroupHeight() {
  const grid = useGraphiteGrid({
    initial: {
      columnHeaderGroupHeight: 80,
      // other grid properties
    },
  });
 
  // ...
}