Skip to main content
The Table component displays data from queries in a tabular format. It uses code mode exclusively to give you full control over data transformation.

What it does

  • Displays rows and columns from query results
  • Supports scrolling for large datasets
  • Resizable both horizontally and vertically
  • Always uses code mode for data transformation

Configuration

The Table is configured entirely through its transform code. There’s no basic mode—you write a transform function that returns the data to display.

Transform function

Your transform function must return an object with headers and rows:
function transform(): { headers: string[]; rows: RowObject[] } {
  const data = query('my-query');

  return {
    headers: ['Name', 'Email', 'Created'],
    rows: data.rows,
  };
}

Return type

{
  headers: string[];           // Column headers to display
  rows: Record<string, any>[]; // Array of row objects
}

Available functions

Inside your transform, you can use:
FunctionReturnsDescription
query(slug){ columns, rows, count, executedAt }Get data from a query by its slug
input(slug){ value, displayName }Get value from an input component

Examples

Basic query display

function transform(): { headers: string[]; rows: RowObject[] } {
  const data = query('users-query');

  return {
    headers: data.columns,
    rows: data.rows,
  };
}

Custom column headers

function transform(): { headers: string[]; rows: RowObject[] } {
  const data = query('users-query');

  return {
    headers: ['Full Name', 'Email Address', 'Sign Up Date'],
    rows: data.rows.map(row => ({
      'Full Name': row.name,
      'Email Address': row.email,
      'Sign Up Date': row.created_at,
    })),
  };
}

Filter based on input

function transform(): { headers: string[]; rows: RowObject[] } {
  const data = query('orders-query');
  const statusFilter = input('simple-select-abc');

  const filtered = data.rows.filter(row =>
    row.status === statusFilter.value
  );

  return {
    headers: ['Order ID', 'Customer', 'Status', 'Total'],
    rows: filtered,
  };
}

Computed columns

function transform(): { headers: string[]; rows: RowObject[] } {
  const data = query('users-query');

  return {
    headers: ['Name', 'Email', 'Domain'],
    rows: data.rows.map(row => ({
      ...row,
      domain: String(row.email).split('@')[1],
    })),
  };
}

Format dates and numbers

function transform(): { headers: string[]; rows: RowObject[] } {
  const data = query('orders-query');

  return {
    headers: ['Order', 'Date', 'Amount'],
    rows: data.rows.map(row => ({
      order: row.id,
      date: new Date(String(row.created_at)).toLocaleDateString(),
      amount: `$${Number(row.total).toFixed(2)}`,
    })),
  };
}

State

The Table component reads from state but doesn’t write to it. It can access:
  • Query results — via query(slug)
  • Input values — via input(slug)
See the State page for details on how state flows through your app.

Tips

  1. Keep transforms fast — Transforms run whenever data changes, so avoid expensive operations
  2. Handle missing data — Check for null/undefined before accessing nested properties
  3. Use descriptive headers — Your users will see these in the table header
  4. Filter in SQL when possible — For large datasets, filter at the database level for better performance