Skip to main content

Import

import { table, tableRow, tableCell, tableHeader } from '@frontmcp/ui';

Basic Usage

const html = table({
  headers: ['Name', 'Email', 'Role'],
  rows: [
    ['John Doe', '[email protected]', 'Admin'],
    ['Jane Smith', '[email protected]', 'Editor'],
    ['Bob Wilson', '[email protected]', 'Viewer'],
  ],
});

With Objects

Pass objects with a columns configuration:
const html = table({
  columns: [
    { key: 'name', header: 'Name' },
    { key: 'email', header: 'Email' },
    { key: 'role', header: 'Role' },
  ],
  data: [
    { name: 'John Doe', email: '[email protected]', role: 'Admin' },
    { name: 'Jane Smith', email: '[email protected]', role: 'Editor' },
    { name: 'Bob Wilson', email: '[email protected]', role: 'Viewer' },
  ],
});

Variants

// Default - alternating row colors
table({ variant: 'default', headers: [...], rows: [...] })

// Bordered - visible cell borders
table({ variant: 'bordered', headers: [...], rows: [...] })

// Striped - zebra striping
table({ variant: 'striped', headers: [...], rows: [...] })

// Compact - reduced padding
table({ variant: 'compact', headers: [...], rows: [...] })

Custom Cell Rendering

Use the render function for custom cell content:
import { table, badge, button } from '@frontmcp/ui';

const html = table({
  columns: [
    { key: 'name', header: 'Name' },
    { key: 'status', header: 'Status', render: (value) => badge(value, {
      variant: value === 'Active' ? 'success' : 'default'
    })},
    { key: 'actions', header: 'Actions', render: (_, row) => button('Edit', {
      variant: 'ghost',
      size: 'sm',
      htmx: { get: `/api/users/${row.id}/edit`, target: '#modal' },
    })},
  ],
  data: [
    { id: 1, name: 'John Doe', status: 'Active' },
    { id: 2, name: 'Jane Smith', status: 'Inactive' },
  ],
});

Column Alignment

const html = table({
  columns: [
    { key: 'item', header: 'Item', align: 'left' },
    { key: 'quantity', header: 'Qty', align: 'center' },
    { key: 'price', header: 'Price', align: 'right' },
  ],
  data: [...],
});

Column Widths

const html = table({
  columns: [
    { key: 'id', header: 'ID', width: '80px' },
    { key: 'name', header: 'Name', width: '200px' },
    { key: 'description', header: 'Description' },  // flexible
    { key: 'actions', header: '', width: '100px' },
  ],
  data: [...],
});

Sortable Headers

Add sorting indicators (visual only - implement sorting logic separately):
const html = table({
  columns: [
    { key: 'name', header: 'Name', sortable: true, sortDirection: 'asc' },
    { key: 'date', header: 'Date', sortable: true },
    { key: 'status', header: 'Status' },
  ],
  data: [...],
  onSort: {
    // HTMX attributes for sort action
    get: '/api/users',
    target: '#user-table',
  },
});

Empty State

Show a message when no data:
const html = table({
  headers: ['Name', 'Email', 'Role'],
  rows: [],
  emptyMessage: 'No users found. Try adjusting your search filters.',
});

With Caption

const html = table({
  caption: 'Monthly Sales Report - Q4 2025',
  headers: ['Month', 'Revenue', 'Growth'],
  rows: [
    ['October', '$45,000', '+12%'],
    ['November', '$52,000', '+15%'],
    ['December', '$61,000', '+17%'],
  ],
});

Responsive Tables

Tables automatically become horizontally scrollable on small screens. Use the responsive wrapper:
const html = table({
  responsive: true,
  headers: ['ID', 'Name', 'Email', 'Phone', 'Address', 'City', 'Country'],
  rows: [...],
});

HTMX Integration

Load table data dynamically:
// Initial table with HTMX loader
const html = `
<div id="user-table" hx-get="/api/users" hx-trigger="load">
  Loading...
</div>
`;

// Server returns table HTML
const tableHtml = table({
  headers: ['Name', 'Email'],
  rows: usersFromDatabase,
});

Pagination

const html = table({
  headers: ['Name', 'Email', 'Role'],
  rows: currentPageRows,
  footer: `
    <div class="flex justify-between items-center mt-4">
      <span class="text-sm text-gray-500">
        Showing 1-10 of 45 results
      </span>
      <div class="flex gap-2">
        ${button('Previous', {
          variant: 'outline',
          size: 'sm',
          htmx: { get: '/api/users?page=1', target: '#table-container' },
        })}
        ${button('Next', {
          variant: 'outline',
          size: 'sm',
          htmx: { get: '/api/users?page=3', target: '#table-container' },
        })}
      </div>
    </div>
  `,
});

Complete Example

import { card, table, badge, button, input } from '@frontmcp/ui';

const usersTable = card(`
  <div class="mb-4">
    ${input({
      name: 'search',
      placeholder: 'Search users...',
      iconBefore: '🔍',
      htmx: {
        get: '/api/users/search',
        trigger: 'keyup changed delay:300ms',
        target: '#users-table',
      },
    })}
  </div>

  <div id="users-table">
    ${table({
      variant: 'striped',
      columns: [
        { key: 'name', header: 'Name', sortable: true },
        { key: 'email', header: 'Email' },
        {
          key: 'status',
          header: 'Status',
          render: (status) => badge(status, {
            variant: status === 'Active' ? 'success' : 'default',
          }),
        },
        {
          key: 'actions',
          header: '',
          align: 'right',
          render: (_, user) => `
            ${button('Edit', { variant: 'ghost', size: 'sm' })}
            ${button('Delete', { variant: 'ghost', size: 'sm' })}
          `,
        },
      ],
      data: users,
      emptyMessage: 'No users found',
    })}
  </div>
`, { title: 'Users' });

API Reference

table(options)

OptionTypeDefaultDescription
headersstring[]-Column headers (simple mode)
rowsstring[][]-Row data (simple mode)
columnsColumn[]-Column config (object mode)
dataobject[]-Row data (object mode)
variant'default' | 'bordered' | 'striped' | 'compact''default'Table style
responsivebooleantrueHorizontal scroll on small screens
captionstring-Table caption
emptyMessagestring-Message when no data
footerstring-Footer HTML
classNamestring-Additional CSS classes

Column Configuration

OptionTypeDescription
keystringProperty key in data objects
headerstringColumn header text
render(value, row) => stringCustom cell renderer
align'left' | 'center' | 'right'Text alignment
widthstringColumn width (CSS value)
sortablebooleanShow sort indicator
sortDirection'asc' | 'desc'Current sort direction

Returns

string - HTML string for the table element.