Canvas: Component Events

Canvas components support HTMLElement-like event handlers: onClick, onDoubleClick, onMouseDown, onMouseUp, onMouseEnter, onMouseLeave. Use event.preventDefault() to suppress default actions (e.g. Link navigation).

1. onClick

Click Text / Link / Chip. Link's preventDefault() blocks URL open.

2. onMouseEnter / onMouseLeave

Hover over Badge / Tag / Rating cells. Not hovering

3. Combined (click + dblclick + mousedown + mouseup)

All events fire in DOM order: mousedown → mouseup → click → dblclick.

Event Log

Interact with the grids to see events here

Code

import {
  Grid,
  createColumnHelper,
  Text,
  Link,
  Chip,
  type GridCellEvent,
} from "@ohah/react-wasm-table";

const helper = createColumnHelper<{ name: string; dept: string }>();

const columns = [
  helper.accessor("name", {
    header: "Name",
    size: 120,
    cell: (info) => (
      <Text
        value={info.getValue()}
        fontWeight="bold"
        onClick={(e: GridCellEvent) => console.log("clicked", info.getValue())}
      />
    ),
  }),
  helper.accessor("dept", {
    header: "Dept (Link)",
    size: 130,
    cell: (info) => (
      <Link
        value={info.getValue()}
        href={`#${info.getValue().toLowerCase()}`}
        onClick={(e: GridCellEvent) => {
          e.preventDefault();
          console.log("link clicked", info.getValue());
        }}
      />
    ),
  }),
];

<Grid data={data} columns={columns} width={400} height={200} rowHeight={36} />;

Table API Code

import {
  Table,
  useReactTable,
  flexRender,
  getCoreRowModel,
  Thead,
  Tbody,
  Tr,
  Th,
  Td,
  createColumnHelper,
  Text,
  Link,
  Chip,
  type GridCellEvent,
} from "@ohah/react-wasm-table";

const helper = createColumnHelper<{ name: string; dept: string }>();

const columns = [
  helper.accessor("name", {
    header: "Name",
    size: 120,
    cell: (info) => (
      <Text
        value={info.getValue()}
        fontWeight="bold"
        onClick={(e: GridCellEvent) => console.log("clicked", info.getValue())}
      />
    ),
  }),
  helper.accessor("dept", {
    header: "Dept (Link)",
    size: 130,
    cell: (info) => (
      <Link
        value={info.getValue()}
        href={`#${info.getValue().toLowerCase()}`}
        onClick={(e: GridCellEvent) => {
          e.preventDefault();
          console.log("link clicked", info.getValue());
        }}
      />
    ),
  }),
];

const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel() });

<Table table={table} width={400} height={200} rowHeight={36}>
  <Thead>
    {table.getHeaderGroups().map((hg) => (
      <Tr key={hg.id}>
        {hg.headers.map((h) => (
          <Th key={h.id} colSpan={h.colSpan}>
            {h.isPlaceholder ? null : flexRender(h.column.columnDef.header, h.getContext())}
          </Th>
        ))}
      </Tr>
    ))}
  </Thead>
  <Tbody>
    {table.getRowModel().rows.map((row) => (
      <Tr key={row.id}>
        {row.getVisibleCells().map((cell) => (
          <Td key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</Td>
        ))}
      </Tr>
    ))}
  </Tbody>
</Table>;