Files
sigpro-ui/docs/components/table.md
2026-04-03 01:41:07 +02:00

12 KiB
Raw Blame History

Table

Data table component with sorting, pagination, zebra stripes, pin rows, and custom cell rendering.

Tag

Table

Props

Prop Type Default Description
items Array | Signal<Array> [] Data array to display
columns Array<Column> [] Column definitions
keyFn function (item, idx) => idx Unique key function for rows
zebra boolean | Signal<boolean> false Enable zebra striping
pinRows boolean | Signal<boolean> false Pin header rows on scroll
empty string | VNode 'No data' Content to show when no data
class string '' Additional CSS classes (DaisyUI + Tailwind)

Column Structure

Property Type Description
label string Column header text
key string Property key to display from item
render function(item, index) Custom render function for cell content
class string Additional CSS classes for column cells
footer string | VNode Footer content for the column

Styling

Table supports all daisyUI Table classes:

Category Keywords Description
Base table Base table styling
Variant table-zebra Zebra striping
Size table-xs, table-sm, table-md, table-lg, table-xl Table scale
Feature table-pin-rows, table-pin-cols Pin headers/columns

For further details, check the daisyUI Table Documentation Full reference for CSS classes.

Live Examples

Basic Table

Live Demo

const BasicDemo = () => {
  const users = [
    { id: 1, name: 'John Doe', email: 'john@example.com', role: 'Admin' },
    { id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'User' },
    { id: 3, name: 'Bob Johnson', email: 'bob@example.com', role: 'Editor' }
  ];
  
  return Table({
    items: users,
    columns: [
      { label: 'ID', key: 'id' },
      { label: 'Name', key: 'name' },
      { label: 'Email', key: 'email' },
      { label: 'Role', key: 'role' }
    ]
  });
};
$mount(BasicDemo, '#demo-basic');

With Zebra Stripes

Live Demo

const ZebraDemo = () => {
  const products = [
    { id: 1, name: 'Laptop', price: '$999', stock: 15 },
    { id: 2, name: 'Mouse', price: '$29', stock: 42 },
    { id: 3, name: 'Keyboard', price: '$79', stock: 28 },
    { id: 4, name: 'Monitor', price: '$299', stock: 12 }
  ];
  
  return Table({
    items: products,
    columns: [
      { label: 'Product', key: 'name' },
      { label: 'Price', key: 'price' },
      { label: 'Stock', key: 'stock' }
    ],
    zebra: true
  });
};
$mount(ZebraDemo, '#demo-zebra');

With Custom Cell Rendering

Live Demo

const CustomDemo = () => {
  const orders = [
    { id: 101, customer: 'Alice', amount: 250, status: 'completed' },
    { id: 102, customer: 'Bob', amount: 89, status: 'pending' },
    { id: 103, customer: 'Charlie', amount: 450, status: 'shipped' }
  ];
  
  return Table({
    items: orders,
    columns: [
      { label: 'Order ID', key: 'id' },
      { label: 'Customer', key: 'customer' },
      { 
        label: 'Amount', 
        key: 'amount',
        render: (item) => `$${item.amount}`
      },
      { 
        label: 'Status', 
        key: 'status',
        render: (item) => {
          const statusClass = {
            completed: 'badge badge-success',
            pending: 'badge badge-warning',
            shipped: 'badge badge-info'
          };
          return Span({ class: statusClass[item.status] }, item.status);
        }
      }
    ],
    zebra: true
  });
};
$mount(CustomDemo, '#demo-custom');

With Footers

Live Demo

const FooterDemo = () => {
  const sales = [
    { month: 'January', revenue: 12500, expenses: 8900 },
    { month: 'February', revenue: 14200, expenses: 9200 },
    { month: 'March', revenue: 16800, expenses: 10100 }
  ];
  
  const totalRevenue = sales.reduce((sum, item) => sum + item.revenue, 0);
  const totalExpenses = sales.reduce((sum, item) => sum + item.expenses, 0);
  
  return Table({
    items: sales,
    columns: [
      { label: 'Month', key: 'month' },
      { 
        label: 'Revenue', 
        key: 'revenue',
        render: (item) => `$${item.revenue.toLocaleString()}`,
        footer: `Total: $${totalRevenue.toLocaleString()}`
      },
      { 
        label: 'Expenses', 
        key: 'expenses',
        render: (item) => `$${item.expenses.toLocaleString()}`,
        footer: `Total: $${totalExpenses.toLocaleString()}`
      },
      { 
        label: 'Profit', 
        render: (item) => `$${(item.revenue - item.expenses).toLocaleString()}`,
        footer: `$${(totalRevenue - totalExpenses).toLocaleString()}`
      }
    ],
    zebra: true
  });
};
$mount(FooterDemo, '#demo-footer');

Empty State

Live Demo

const EmptyDemo = () => {
  const emptyList = [];
  
  return Table({
    items: emptyList,
    columns: [
      { label: 'ID', key: 'id' },
      { label: 'Name', key: 'name' }
    ],
    empty: Div({ class: 'flex flex-col items-center gap-2 p-4' }, [
      Span({ class: 'text-2xl' }, '📭'),
      Span({}, 'No records found')
    ])
  });
};
$mount(EmptyDemo, '#demo-empty');

Reactive Data

Live Demo

const ReactiveDemo = () => {
  const filter = $('all');
  const tasks = $([
    { id: 1, title: 'Complete documentation', completed: true },
    { id: 2, title: 'Review pull requests', completed: false },
    { id: 3, title: 'Deploy to production', completed: false },
    { id: 4, title: 'Update dependencies', completed: true }
  ]);
  
  const filteredTasks = () => {
    if (filter() === 'completed') {
      return tasks().filter(t => t.completed);
    } else if (filter() === 'pending') {
      return tasks().filter(t => !t.completed);
    }
    return tasks();
  };
  
  const addTask = () => {
    const newId = Math.max(...tasks().map(t => t.id), 0) + 1;
    tasks([...tasks(), { id: newId, title: `Task ${newId}`, completed: false }]);
  };
  
  return Div({ class: 'flex flex-col gap-4' }, [
    Div({ class: 'flex gap-2' }, [
      Button({ 
        class: 'btn btn-sm',
        onclick: () => filter('all')
      }, 'All'),
      Button({ 
        class: 'btn btn-sm',
        onclick: () => filter('completed')
      }, 'Completed'),
      Button({ 
        class: 'btn btn-sm',
        onclick: () => filter('pending')
      }, 'Pending'),
      Button({ 
        class: 'btn btn-sm btn-primary',
        onclick: addTask
      }, 'Add Task')
    ]),
    Table({
      items: filteredTasks,
      columns: [
        { label: 'ID', key: 'id' },
        { label: 'Title', key: 'title' },
        {
          label: 'Status',
          render: (item) => item.completed 
            ? Span({ class: 'badge badge-success' }, '✓ Done')
            : Span({ class: 'badge badge-warning' }, '○ Pending')
        }
      ],
      zebra: true
    })
  ]);
};
$mount(ReactiveDemo, '#demo-reactive');

With Actions

Live Demo

const ActionsDemo = () => {
  const users = $([
    { id: 1, name: 'John Doe', email: 'john@example.com', active: true },
    { id: 2, name: 'Jane Smith', email: 'jane@example.com', active: false },
    { id: 3, name: 'Bob Johnson', email: 'bob@example.com', active: true }
  ]);
  
  const deleteUser = (id) => {
    users(users().filter(u => u.id !== id));
    Toast('User deleted', 'alert-info', 2000);
  };
  
  const toggleActive = (id) => {
    users(users().map(u => 
      u.id === id ? { ...u, active: !u.active } : u
    ));
  };
  
  return Table({
    items: users,
    columns: [
      { label: 'ID', key: 'id' },
      { label: 'Name', key: 'name' },
      { label: 'Email', key: 'email' },
      {
        label: 'Status',
        render: (item) => item.active
          ? Span({ class: 'badge badge-success' }, 'Active')
          : Span({ class: 'badge badge-ghost' }, 'Inactive')
      },
      {
        label: 'Actions',
        render: (item) => Div({ class: 'flex gap-1' }, [
          Button({
            class: 'btn btn-xs btn-ghost',
            onclick: () => toggleActive(item.id)
          }, item.active ? 'Deactivate' : 'Activate'),
          Button({
            class: 'btn btn-xs btn-error',
            onclick: () => deleteUser(item.id)
          }, 'Delete')
        ])
      }
    ],
    zebra: true
  });
};
$mount(ActionsDemo, '#demo-actions');

All Variants

Live Demo

const VariantsDemo = () => {
  const data = [
    { id: 1, name: 'Item 1', value: 100 },
    { id: 2, name: 'Item 2', value: 200 },
    { id: 3, name: 'Item 3', value: 300 }
  ];
  
  return Div({ class: 'flex flex-col gap-6' }, [
    Div({ class: 'text-sm font-bold' }, 'Default Table'),
    Table({
      items: data,
      columns: [
        { label: 'ID', key: 'id' },
        { label: 'Name', key: 'name' },
        { label: 'Value', key: 'value' }
      ]
    }),
    
    Div({ class: 'text-sm font-bold mt-4' }, 'Zebra Stripes'),
    Table({
      items: data,
      columns: [
        { label: 'ID', key: 'id' },
        { label: 'Name', key: 'name' },
        { label: 'Value', key: 'value' }
      ],
      zebra: true
    }),
    
    Div({ class: 'text-sm font-bold mt-4' }, 'Compact Table'),
    Table({
      items: data,
      columns: [
        { label: 'ID', key: 'id' },
        { label: 'Name', key: 'name' },
        { label: 'Value', key: 'value' }
      ],
      class: 'table-compact'
    })
  ]);
};
$mount(VariantsDemo, '#demo-variants');