Lattice Grid Buy a licence

react data grid · filtering

React Grid: Filtering

A per-column filter menu with the operators each type supports, and an inline filter row that writes the exact same condition, so a reader who prefers typing under the header gets to, without a second filtering system underneath.

Also in: Angular

Install and import

npm install @toclocoinc/lattice-grid
# free on localhost; a production domain needs a licence key (see /pricing/)

The files

lattice.ts

// lattice.ts
import React from 'react';
import { createGrid } from '@toclocoinc/lattice-grid';
import '@toclocoinc/lattice-grid/css';
import { createLatticeGrid } from '@toclocoinc/lattice-grid/modules/react';

export const LatticeGrid = createLatticeGrid({ React, createGrid });

ServiceFiltering.tsx

// ServiceFiltering.tsx
import React, { useRef, useState } from 'react';
import { createRoot } from 'react-dom/client';
import { LatticeGrid } from './lattice';

// columnDefaults turns the per-column filter menu on across the board; each
// column offers the operators that suit its own type.
const columns = [
  { field: 'service', title: 'Service', layout: { pin: 'start', width: 140 } },
  { field: 'team', title: 'Team', filter: { type: 'set' } },
  { field: 'owner', title: 'Owner', filter: { type: 'set' } },
  { field: 'tier', title: 'Tier',
    cell: { decoration: 'pill', variant: { map: { gold: 'warning', silver: 'neutral', bronze: 'info' } } } },
  { field: 'state', title: 'State',
    cell: { decoration: 'dot', variant: { map: { healthy: 'success', degraded: 'warning', failing: 'danger', unknown: 'neutral' } } } },
  { field: 'region', title: 'Region', filter: { type: 'set' } },
  { field: 'active', title: 'Active', type: 'boolean' },
  { field: 'deprecated', title: 'Deprecated', type: 'boolean' },
];

const rows = [/* service records */];

// filterRow is the same grid.set('filterRow', value) call an application
// would make; the toggle below drives it through the ref, not a filter
// system of its own.
function ServiceFiltering() {
  const ref = useRef<{ grid: any } | null>(null);
  const [filterRow, setFilterRow] = useState(false);

  const toggle = (on: boolean) => {
    setFilterRow(on);
    ref.current?.grid?.set('filterRow', on);
  };

  return (
    <>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 10 }}>
        <span>Filter row</span>
        <button type="button" aria-pressed={!filterRow} onClick={() => toggle(false)}>Off</button>
        <button type="button" aria-pressed={filterRow} onClick={() => toggle(true)}>On</button>
      </div>
      <LatticeGrid
        ref={ref}
        rowKey="id"
        filterRow={false}
        columnDefaults={{ filter: true }}
        toolPanel={{ side: 'left', panels: ['filters', 'columns'], actions: ['restore'], exportName: 'lattice-demo' }}
        columns={columns}
        rows={rows}
        style={{ height: '460px' }}
      />
    </>
  );
}

createRoot(document.getElementById('service-filtering')!).render(<ServiceFiltering />);

See it running

Building…
Loading a live grid…

Open this demo's React tab →

Working in React

The row is a config key, not a second filter store. Toggling filterRow through grid.set('filterRow', value) shows or hides the inline row; whatever a reader types there and whatever they pick from a column's menu land on the same condition tree, so the two never disagree.

Reaching the grid to toggle it. ref.current.grid is null until after mount, which is why the toggle above reads it inside an event handler rather than at render time.

columnDefaults is mount-time. It sets the starting shape for every column that does not declare its own filter; changing it after mount does not retroactively rewrite columns already configured. Give the grid a new key if you need a full reconfiguration.

Related