---
id: "packages/active-grid/examples"
title: "Examples"
description: "Every working example of active-grid on one page, with its kind and the file that renders it."
url: "/packages/active-grid/examples"
locale: "en"
revision: "0c929fd356171ae0"
---

# Examples

The kinds are explained on [Client, server and simulation](/packages/active-grid/client-server-and-simulation).
The data is a seeded set of invented orders: every reader sees the same rows.

**Example: Orders in client mode**

Client: Runs entirely in your browser. Source: `examples/grid/client-orders.tsx`.

```tsx
// apps/docs/examples/grid/client-orders.tsx
'use client';

import '@workspace/active-grid/styles.css';

import {useMemo} from 'react';
import {generateOrders, type Order} from '@/lib/examples/orders';

import {
  composePresentationContext,
  toIanaTimeZone,
} from '@workspace/active-format';
import {
  ActiveGrid,
  createColumnHelper,
  englishGridTranslator,
  type GridColumnDef,
} from '@workspace/active-grid';

// The presentation: language, notation and the time zone the date filter
// needs for its relative presets and calendar.
const presentation = composePresentationContext(
  'en-GB',
  null,
  toIanaTimeZone('Europe/Amsterdam'),
);

const STATUS = [
  {label: 'Pending', value: 'pending'},
  {label: 'Processing', value: 'processing'},
  {label: 'Shipped', value: 'shipped'},
  {label: 'Delivered', value: 'delivered'},
  {label: 'Cancelled', value: 'cancelled'},
];

const ch = createColumnHelper<Order>();
const columns: GridColumnDef<Order>[] = [
  ch.accessor('id', {header: 'Order', meta: {filterType: 'text'}}),
  ch.accessor('customer', {header: 'Customer', meta: {filterType: 'text'}}),
  ch.accessor('category', {
    header: 'Category',
    meta: {filterType: 'select'},
  }),
  ch.accessor('quantity', {header: 'Qty', type: 'number'}),
  ch.accessor('total', {
    header: 'Total',
    type: 'currency',
    meta: {currencyCode: 'EUR', filterType: 'number'},
  }),
  ch.accessor('orderDate', {header: 'Ordered', type: 'date'}),
  ch.accessor('status', {
    header: 'Status',
    type: 'badge',
    meta: {
      filterType: 'select',
      filterOptions: STATUS,
      statusTones: {
        pending: 'warning',
        processing: 'info',
        shipped: 'info',
        delivered: 'success',
        cancelled: 'danger',
      },
    },
  }),
];

/** Client mode: all 500 rows are in the browser; the grid sorts, filters and pages them there. */
export default function ClientOrders() {
  const data = useMemo(() => generateOrders(500), []);
  return (
    <ActiveGrid<Order>
      gridId="docs-client-orders"
      mode="client"
      data={data}
      columns={columns}
      height={420}
      locale={presentation}
      t={englishGridTranslator}
      enableRowSelection
      pagination={{enabled: true, pageSizeOptions: [10, 25, 50]}}
      toolbar={{search: {enabled: true}, showColumnChooser: true}}
    />
  );
}
```

**Example: Server mode against an imitated server**

Simulation: A server imitated in your browser: shows the interaction, not a working server integration. Source: `examples/grid/simulated-orders.tsx`.

```tsx
// apps/docs/examples/grid/simulated-orders.tsx
'use client';

import '@workspace/active-grid/styles.css';

import {useCallback, useMemo, useState} from 'react';
import {generateOrders, queryOrders, type Order} from '@/lib/examples/orders';

import {
  composePresentationContext,
  toIanaTimeZone,
} from '@workspace/active-format';
import {
  ActiveGrid,
  createColumnHelper,
  englishGridTranslator,
  scalarField,
  type GridColumnDef,
  type ServerFetchFunction,
} from '@workspace/active-grid';
import {
  Field,
  FieldLabel,
} from '@workspace/active-ui/components/primitives/field';
import {Switch} from '@workspace/active-ui/components/primitives/switch';

const presentation = composePresentationContext(
  'en-GB',
  null,
  toIanaTimeZone('Europe/Amsterdam'),
);

const ch = createColumnHelper<Order>();
const columns: GridColumnDef<Order>[] = [
  ch.accessor('id', {
    header: 'Order',
    meta: {filterType: 'text'},
    server: scalarField(),
  }),
  ch.accessor('product', {
    header: 'Product',
    meta: {filterType: 'text'},
    server: scalarField(),
  }),
  ch.accessor('quantity', {
    header: 'Qty',
    type: 'number',
    server: scalarField(),
  }),
  ch.accessor('total', {
    header: 'Total',
    type: 'currency',
    meta: {currencyCode: 'EUR', filterType: 'number'},
    server: scalarField(),
  }),
];

const wait = (ms: number, signal: AbortSignal) =>
  new Promise<void>((resolve, reject) => {
    const timer = setTimeout(resolve, ms);
    signal.addEventListener('abort', () => {
      clearTimeout(timer);
      reject(signal.reason);
    });
  });

/**
 * Server mode against a server imitated in the browser: a fetchFn with a
 * delay over rows that are already here, and a switch that makes it fail.
 * It shows the grid's loading, paging and error states, not a server.
 */
export default function SimulatedOrders() {
  const orders = useMemo(() => generateOrders(2000), []);
  const [failing, setFailing] = useState(false);
  const fetchOrders = useCallback<ServerFetchFunction<Order>>(
    async ({signal, ...params}) => {
      await wait(600, signal);
      if (failing) throw new Error('The simulated server is down');
      return queryOrders(orders, params);
    },
    [orders, failing],
  );
  return (
    <div className="flex flex-col gap-4">
      <Field orientation="horizontal">
        <Switch
          id="simulated-failure"
          // Named in the server HTML already, not only after hydration.
          aria-labelledby="simulated-failure-label"
          checked={failing}
          onCheckedChange={setFailing}
        />
        <FieldLabel id="simulated-failure-label" htmlFor="simulated-failure">
          Make the next request fail
        </FieldLabel>
      </Field>
      <ActiveGrid<Order>
        key={String(failing)}
        gridId="docs-simulated-orders"
        mode="server"
        fetchFn={fetchOrders}
        columns={columns}
        height={360}
        locale={presentation}
        t={englishGridTranslator}
        pagination={{enabled: true}}
        serverOptions={{blockSize: 25, retryCount: 0}}
      />
    </div>
  );
}
```

**Example: Server mode against a real route**

Server: Calls a real route of this site, which does the work on the server. Source: `examples/grid/server-orders.tsx`.

```tsx
// apps/docs/examples/grid/server-orders.tsx
'use client';

import '@workspace/active-grid/styles.css';

import {useCallback, useState} from 'react';
import type {Order} from '@/lib/examples/orders';

import {
  composePresentationContext,
  toIanaTimeZone,
} from '@workspace/active-format';
import {
  ActiveGrid,
  createColumnHelper,
  englishGridTranslator,
  globalField,
  scalarField,
  type GridColumnDef,
  type PagedResponse,
  type ServerFetchFunction,
} from '@workspace/active-grid';

const presentation = composePresentationContext(
  'en-GB',
  null,
  toIanaTimeZone('Europe/Amsterdam'),
);

const ch = createColumnHelper<Order>();
// In server mode the column contract (`server`) declares what the server can
// sort and filter; the grid offers exactly that, and nothing the server would
// refuse.
const columns: GridColumnDef<Order>[] = [
  ch.accessor('id', {
    header: 'Order',
    meta: {filterType: 'text'},
    server: {...scalarField(), global: globalField()},
  }),
  ch.accessor('customer', {
    header: 'Customer',
    meta: {filterType: 'text'},
    server: {...scalarField(), global: globalField()},
  }),
  ch.accessor('category', {
    header: 'Category',
    meta: {filterType: 'select'},
    server: {...scalarField(), global: globalField()},
  }),
  ch.accessor('total', {
    header: 'Total',
    type: 'currency',
    meta: {currencyCode: 'EUR', filterType: 'number'},
    server: scalarField(),
  }),
  ch.accessor('orderDate', {
    header: 'Ordered',
    type: 'date',
    meta: {filterType: 'date'},
    server: scalarField(),
  }),
  ch.accessor('status', {
    header: 'Status',
    meta: {filterType: 'select'},
    server: scalarField(),
  }),
];

interface Exchange {
  n: number;
  request: string;
  answer: string;
}

/**
 * Server mode against a real route of this site. The browser sends the
 * grid's request (page, block size, sorting, filters, search); the server
 * filters, sorts and pages 5,000 orders and answers with one block.
 */
export default function ServerOrders() {
  const [log, setLog] = useState<Exchange[]>([]);
  const fetchOrders = useCallback<ServerFetchFunction<Order>>(
    async ({signal, ...params}) => {
      const body = JSON.stringify(params);
      const response = await fetch('/api/examples/grid/orders', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body,
        signal,
      });
      const text = await response.text();
      if (!response.ok) throw new Error(`The server refused: ${text}`);
      const page = JSON.parse(text) as PagedResponse<Order>;
      setLog((list) =>
        [
          {
            n: (list[0]?.n ?? 0) + 1,
            request: body,
            answer: `${page.data.length} rows of ${page.totalCount}, ${(text.length / 1024).toFixed(1)} kB`,
          },
          ...list,
        ].slice(0, 5),
      );
      return page;
    },
    [],
  );
  return (
    <div className="flex flex-col gap-4">
      <ActiveGrid<Order>
        gridId="docs-server-orders"
        mode="server"
        fetchFn={fetchOrders}
        columns={columns}
        height={380}
        locale={presentation}
        t={englishGridTranslator}
        pagination={{enabled: true, pageSizeOptions: [10, 25, 50]}}
        toolbar={{search: {enabled: true}}}
        serverOptions={{blockSize: 50, retryCount: 0}}
      />
      <section aria-label="Requests to the server" data-request-log>
        <h3 className="mb-2 text-sm font-semibold">
          Requests (POST /api/examples/grid/orders)
        </h3>
        <ol className="flex flex-col gap-2">
          {log.map((exchange) => (
            <li
              key={exchange.n}
              className="bg-muted rounded-md p-2 font-mono text-xs break-all"
              data-request={exchange.n}
            >
              <div>
                #{exchange.n} → {exchange.request}
              </div>
              <div className="text-muted-foreground">← {exchange.answer}</div>
            </li>
          ))}
        </ol>
      </section>
    </div>
  );
}
```
