ObjectUIObjectUI
Fields

Grid Field

Sub-table field for inline tabular data

The Grid Field component provides an inline table for managing related records or tabular data within a parent record. It displays data in rows and columns with optional editing capabilities.

Basic Usage

Basic Grid

-
{
  "type": "grid",
  "name": "line_items",
  "label": "Line Items",
  "columns": [
    {
      "name": "product",
      "label": "Product",
      "type": "text"
    },
    {
      "name": "quantity",
      "label": "Quantity",
      "type": "number"
    },
    {
      "name": "price",
      "label": "Price",
      "type": "currency"
    }
  ]
}

With Data

Grid with Data

ItemQtyPrice
Widget A229.99
Widget B149.99
Widget C59.99
{
  "type": "grid",
  "name": "order_items",
  "label": "Order Items",
  "columns": [
    {
      "name": "item",
      "label": "Item",
      "type": "text"
    },
    {
      "name": "qty",
      "label": "Qty",
      "type": "number"
    },
    {
      "name": "price",
      "label": "Price",
      "type": "currency"
    }
  ],
  "value": [
    {
      "item": "Widget A",
      "qty": 2,
      "price": 29.99
    },
    {
      "item": "Widget B",
      "qty": 1,
      "price": 49.99
    },
    {
      "item": "Widget C",
      "qty": 5,
      "price": 9.99
    }
  ]
}

Read-Only

Read-Only Grid

2 rows
{
  "type": "grid",
  "name": "transaction_history",
  "label": "Transaction History",
  "columns": [
    {
      "name": "date",
      "label": "Date",
      "type": "date"
    },
    {
      "name": "description",
      "label": "Description",
      "type": "text"
    },
    {
      "name": "amount",
      "label": "Amount",
      "type": "currency"
    }
  ],
  "readonly": true,
  "value": [
    {
      "date": "2024-03-15",
      "description": "Payment received",
      "amount": 100
    },
    {
      "date": "2024-03-14",
      "description": "Service charge",
      "amount": -5
    }
  ]
}

Field Schema

interface GridFieldSchema {
  type: 'grid';
  name: string;                  // Field name/ID
  label?: string;                // Field label
  value?: any[];                 // Array of row objects
  required?: boolean;            // Is field required
  readonly?: boolean;            // Read-only mode
  disabled?: boolean;            // Disabled state
  className?: string;            // Additional CSS classes
  
  // Grid Options
  columns?: ColumnDefinition[];  // Column definitions
}

interface ColumnDefinition {
  name: string;                  // Column field name
  label: string;                 // Column header label
  type: string;                  // Field type (text, number, etc.)
  width?: string;                // Column width
  editable?: boolean;            // Is column editable
  required?: boolean;            // Is column required
  [key: string]: any;            // Additional field-specific props
}

Column Types

Columns can use any field type:

columns: [
  { name: 'name', label: 'Name', type: 'text', required: true },
  { name: 'quantity', label: 'Qty', type: 'number', min: 1 },
  { name: 'price', label: 'Price', type: 'currency', currency: 'USD' },
  { name: 'date', label: 'Date', type: 'date' },
  { name: 'status', label: 'Status', type: 'select', options: [...] },
  { name: 'active', label: 'Active', type: 'boolean' }
]

Data Format

Grid data is stored as an array of objects:

const gridValue = [
  { product: 'Item 1', quantity: 2, price: 29.99 },
  { product: 'Item 2', quantity: 1, price: 49.99 },
  { product: 'Item 3', quantity: 5, price: 9.99 }
];

Common Patterns

Invoice Line Items

{
  type: 'grid',
  name: 'line_items',
  label: 'Line Items',
  columns: [
    { name: 'description', label: 'Description', type: 'text', required: true },
    { name: 'quantity', label: 'Quantity', type: 'number', min: 1, required: true },
    { name: 'unit_price', label: 'Unit Price', type: 'currency', required: true },
    { name: 'amount', label: 'Amount', type: 'currency', readonly: true }
  ]
}

Order Details

{
  type: 'grid',
  name: 'order_details',
  label: 'Order Details',
  columns: [
    { name: 'sku', label: 'SKU', type: 'text' },
    { name: 'product', label: 'Product', type: 'lookup', reference_to: 'products' },
    { name: 'quantity', label: 'Qty', type: 'number' },
    { name: 'price', label: 'Price', type: 'currency' },
    { name: 'discount', label: 'Discount', type: 'percent' },
    { name: 'total', label: 'Total', type: 'currency', readonly: true }
  ]
}

Task Checklist

{
  type: 'grid',
  name: 'tasks',
  label: 'Tasks',
  columns: [
    { name: 'task', label: 'Task', type: 'text', required: true },
    { name: 'assigned_to', label: 'Assigned To', type: 'user' },
    { name: 'due_date', label: 'Due Date', type: 'date' },
    { name: 'completed', label: 'Done', type: 'boolean' }
  ]
}

Features

  • Table Display: Clean tabular layout
  • Pagination Preview: Shows first 5 rows with "Showing X of Y" indicator
  • Type-Specific Rendering: Each column renders according to its type
  • Read-Only Mode: Full table view without editing
  • Responsive: Scrollable for many columns

Cell Renderer

In tables/grids, displays row count:

import { GridCellRenderer } from '@object-ui/fields';

// Renders: "5 rows"

Full Grid Functionality

For advanced grid features, use the grid plugin (@object-ui/plugin-grid):

// Basic inline grid (simple display)
{ type: 'grid', name: 'items', columns: [...] }

// Advanced grid with full features (requires plugin)
{
  type: 'plugin:grid',
  bind: 'items',
  props: {
    columns: [...],
    editable: true,      // Plugin feature: inline editing
    sortable: true,      // Plugin feature: column sorting
    filterable: true,    // Plugin feature: filtering
    pagination: { pageSize: 20 }  // Plugin feature: pagination
  }
}

Note: Features like editable, sortable, filterable, and advanced pagination are provided by the @object-ui/plugin-grid package, not the basic grid field.

Use Cases

  • Invoice/Order Line Items: Product lines, services
  • Expense Reports: Expense entries, receipts
  • Time Tracking: Time entries, work logs
  • Inventory: Stock items, materials
  • Checklists: Task lists, requirements
  • Schedules: Appointments, bookings
  • Configurations: Settings lists, parameters

Backend Storage

Grid data is typically stored as JSON:

// Database column type: JSONB (PostgreSQL)
interface OrderRecord {
  id: string;
  customer_id: string;
  line_items: Array<{
    product: string;
    quantity: number;
    price: number;
  }>;
}

// Store in database
const order = {
  customer_id: 'CUST-123',
  line_items: [
    { product: 'Widget A', quantity: 2, price: 29.99 },
    { product: 'Widget B', quantity: 1, price: 49.99 }
  ]
};

await db.insert('orders', order);

Validation

Example validation for grid data:

const validateGridData = (data: any[], columns: ColumnDefinition[]) => {
  const errors: string[] = [];
  
  data.forEach((row, index) => {
    columns.forEach(col => {
      // Check required columns
      if (col.required && !row[col.name]) {
        errors.push(`Row ${index + 1}: ${col.label} is required`);
      }
      
      // Validate by type
      if (col.type === 'number' && isNaN(row[col.name])) {
        errors.push(`Row ${index + 1}: ${col.label} must be a number`);
      }
      
      // Check min/max
      if (col.min !== undefined && row[col.name] < col.min) {
        errors.push(`Row ${index + 1}: ${col.label} must be >= ${col.min}`);
      }
    });
  });
  
  return errors;
};

Integration with Advanced Grid

For full-featured grids, use the @object-ui/plugin-grid package which provides:

  • Inline editing
  • Add/remove rows
  • Sorting and filtering
  • Drag-and-drop reordering
  • Export functionality
  • Formula columns
  • Aggregation rows

On this page