Skip to content

Table

Organizes data into rows and columns, with each row representing a single item and each column representing a specific attribute. Tables provide a structured way to display complex or tabular information clearly.

Usage

Use tables to present datasets, lists, or records where a clear relationship between rows and columns is important. Headers must be descriptive and for large datasets, consider features like sorting or filtering. Do NOT use tables for layout purposes.

API Reference

Component attubute(s)

x-h-table-container
x-h-table
x-h-table-container
x-h-table-header
x-h-table-head
x-h-table-cell
x-h-table-body
x-h-table-row
x-h-table-caption
x-h-table-footer

Attributes

x-h-table-container

AttributeTypeRequiredDescription
data-borderbooleanfalseAdds a border to the table.

x-h-table

AttributeTypeRequiredDescription
data-bordersrows
columns
both
falseAdds borders between rows, columns or both.
data-fixedbooleanfalseFixed table layout. Incompatible with scroll mode.

x-h-table-row

AttributeTypeRequiredDescription
data-stateselectedfalseSets a selected state to the row.
data-hoverablebooleanfalseMakes the row hoverable.
data-activablebooleanfalseMakes the row activable.

x-h-table-head

AttributeTypeRequiredDescription
data-hoverablebooleanfalseMakes the header cell hoverable.
data-activablebooleanfalseMakes the header cell activable.

x-h-table-cell

AttributeTypeRequiredDescription
data-hoverablebooleanfalseMakes the cell hoverable.
data-activablebooleanfalseMakes the cell activable.

Modifiers

x-h-table-container

ModifierDescription
scrollAdds scroll ability to the container.

Examples

Table with scroll


html
<div x-h-table-container.scroll data-border="true" style="max-height: 688px">
  <table x-h-table data-borders="both" x-data="tableData">
    <caption x-h-table-caption>
      Fruits & Vegetables
    </caption>
    <thead x-h-table-header>
      <tr x-h-table-row>
        <th x-h-table-head scope="col">Invoice Number</th>
        <th x-h-table-head scope="col" data-hoverable="true" data-activable="true">
          <div class="flex items-center justify-between">Invoice Date<i role="img" class="size-4" data-lucide="arrow-up-down"></i></div>
        </th>
        <th x-h-table-head scope="col">Customer Name</th>
        <th x-h-table-head scope="col">Due Date</th>
        <th x-h-table-head scope="col">Amount Total</th>
        <th x-h-table-head scope="col">Status</th>
        <th x-h-table-head scope="col">Outstanding Balance</th>
        <th x-h-table-head scope="col">Created By</th>
        <th x-h-table-head scope="col">Last Sent</th>
        <th x-h-table-head scope="col">Tax Amount</th>
        <th x-h-table-head scope="col">Category</th>
        <th x-h-table-head scope="col">Currency</th>
      </tr>
    </thead>
    <tbody x-h-table-body>
      <template x-for="invoice in invoices">
        <tr x-h-table-row data-hoverable="true" data-activable="true">
          <th x-h-table-head x-text="invoice.invoiceNumber"></th>
          <td x-h-table-cell x-text="invoice.invoiceDate"></td>
          <td x-h-table-cell x-text="invoice.customerName"></td>
          <td x-h-table-cell x-text="invoice.dueDate"></td>
          <td x-h-table-cell x-text="invoice.amountTotal"></td>
          <td x-h-table-cell x-text="invoice.status"></td>
          <td x-h-table-cell x-text="invoice.outstandingBalance"></td>
          <td x-h-table-cell x-text="invoice.createdBy"></td>
          <td x-h-table-cell x-text="invoice.lastSent"></td>
          <td x-h-table-cell x-text="invoice.taxAmount"></td>
          <td x-h-table-cell x-text="invoice.category"></td>
          <td x-h-table-cell x-text="invoice.currency"></td>
        </tr>
      </template>
    </tbody>
    <tfoot x-h-table-footer>
      <tr x-h-table-row>
        <th x-h-table-head scope="row">Total Invoices</th>
        <td x-h-table-cell colspan="11" x-text="invoices.length"></td>
      </tr>
    </tfoot>
  </table>
</div>
<script type="text/javascript">
  function randomChoice(arr) {
    return arr[Math.floor(Math.random() * arr.length)];
  }

  function randomFloat(min, max) {
    return Math.random() * (max - min) + min;
  }

  function randomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
  }

  function formatDate(date) {
    const day = date.getDate().toString().padStart(2, '0');
    const month = date.toLocaleString('en-US', { month: 'long' });
    const year = date.getFullYear();
    return `${day} ${month} ${year}`;
  }

  const names = ['Ivan Strashimechkarov', 'Anna Petrova', 'John Doe', 'Maria Gonzalez', 'Liam Smith', 'Emma Johnson', 'Noah Brown', 'Olivia Davis', 'William Wilson', 'Sophia Moore'];

  const categories = ['Consulting', 'Software', 'Design', 'Training', 'Marketing'];
  const statuses = ['paid', 'unpaid', 'overdue', 'partial'];

  function generateInvoices() {
    const baseDate = new Date();
    const invoices = [];
    for (let i = 0; i < 50; i++) {
      const invoiceDate = new Date(baseDate.getTime());
      invoiceDate.setDate(invoiceDate.getDate() + randomInt(0, 240));

      const dueDate = new Date(invoiceDate.getTime());
      dueDate.setDate(dueDate.getDate() + 20);

      const amountTotal = parseFloat(randomFloat(500, 5000).toFixed(2));
      const taxAmount = parseFloat((amountTotal * 0.1).toFixed(2));

      const status = randomChoice(statuses);

      let outstandingBalance;
      if (status === 'partial') {
        outstandingBalance = parseFloat((amountTotal * randomFloat(0.1, 0.65)).toFixed(2));
      } else if (status === 'paid') {
        outstandingBalance = 0.0;
      } else {
        outstandingBalance = amountTotal;
      }

      const invoice = {
        invoiceNumber: `INV-${String(i + 1).padStart(2, '0')}`,
        invoiceDate: formatDate(invoiceDate),
        customerName: randomChoice(names),
        dueDate: formatDate(dueDate),
        amountTotal: amountTotal,
        status: status,
        outstandingBalance: outstandingBalance,
        createdBy: 'admin',
        lastSent: formatDate(invoiceDate),
        taxAmount: taxAmount,
        category: randomChoice(categories),
        currency: 'EUR',
      };

      invoices.push(invoice);
    }
    return invoices;
  }
  lucide.createIcons();
  Alpine.data('tableData', () => ({
    invoices: generateInvoices(),
  }));
</script>

Table with caption


html
<div x-h-table-container data-border="true">
  <table x-h-table data-borders="both">
    <caption x-h-table-caption>
      Fruits & Vegetables
    </caption>
    <thead x-h-table-header>
      <tr x-h-table-row>
        <th x-h-table-head scope="col">Item</th>
        <th x-h-table-head scope="col">Type</th>
      </tr>
    </thead>
    <tbody x-h-table-body>
      <tr x-h-table-row>
        <td x-h-table-head>Cucumber</td>
        <td x-h-table-cell>Vegetable</td>
      </tr>
      <tr x-h-table-row>
        <td x-h-table-head>Banana</td>
        <td x-h-table-cell>Fruit</td>
      </tr>
      <tr x-h-table-row>
        <td x-h-table-head>Asparagus</td>
        <td x-h-table-cell>Vegetable</td>
      </tr>
      <tr x-h-table-row>
        <td x-h-table-head>Onion</td>
        <td x-h-table-cell>Vegetable</td>
      </tr>
      <tr x-h-table-row>
        <td x-h-table-head>Apple</td>
        <td x-h-table-cell>Fruit</td>
      </tr>
    </tbody>
  </table>
</div>

Table with row borders


html
<div x-h-table-container data-border="true">
  <table x-h-table data-borders="rows" data-fixed="true">
    <thead x-h-table-header>
      <tr x-h-table-row>
        <th x-h-table-head scope="col">Item</th>
        <th x-h-table-head scope="col">Type</th>
      </tr>
    </thead>
    <tbody x-h-table-body>
      <tr x-h-table-row>
        <td x-h-table-head>Cucumber</td>
        <td x-h-table-cell>Vegetable</td>
      </tr>
      <tr x-h-table-row>
        <td x-h-table-head>Banana</td>
        <td x-h-table-cell>Fruit</td>
      </tr>
      <tr x-h-table-row>
        <td x-h-table-head>Asparagus</td>
        <td x-h-table-cell>Vegetable</td>
      </tr>
      <tr x-h-table-row>
        <td x-h-table-head>Onion</td>
        <td x-h-table-cell>Vegetable</td>
      </tr>
      <tr x-h-table-row>
        <td x-h-table-head>Apple</td>
        <td x-h-table-cell>Fruit</td>
      </tr>
    </tbody>
  </table>
</div>

Table with column borders


html
<div x-h-table-container data-border="true">
  <table x-h-table data-borders="columns" data-fixed="true">
    <thead x-h-table-header>
      <tr x-h-table-row>
        <th x-h-table-head scope="col">Item</th>
        <th x-h-table-head scope="col">Type</th>
      </tr>
    </thead>
    <tbody x-h-table-body>
      <tr x-h-table-row>
        <td x-h-table-head>Cucumber</td>
        <td x-h-table-cell>Vegetable</td>
      </tr>
      <tr x-h-table-row>
        <td x-h-table-head>Banana</td>
        <td x-h-table-cell>Fruit</td>
      </tr>
      <tr x-h-table-row>
        <td x-h-table-head>Asparagus</td>
        <td x-h-table-cell>Vegetable</td>
      </tr>
      <tr x-h-table-row>
        <td x-h-table-head>Onion</td>
        <td x-h-table-cell>Vegetable</td>
      </tr>
      <tr x-h-table-row>
        <td x-h-table-head>Apple</td>
        <td x-h-table-cell>Fruit</td>
      </tr>
    </tbody>
  </table>
</div>

Table with no borders


html
<div x-h-table-container>
  <table x-h-table data-fixed="true">
    <thead x-h-table-header>
      <tr x-h-table-row>
        <th x-h-table-head scope="col">Item</th>
        <th x-h-table-head scope="col">Type</th>
      </tr>
    </thead>
    <tbody x-h-table-body>
      <tr x-h-table-row>
        <td x-h-table-head>Cucumber</td>
        <td x-h-table-cell>Vegetable</td>
      </tr>
      <tr x-h-table-row>
        <td x-h-table-head>Banana</td>
        <td x-h-table-cell>Fruit</td>
      </tr>
      <tr x-h-table-row>
        <td x-h-table-head>Asparagus</td>
        <td x-h-table-cell>Vegetable</td>
      </tr>
      <tr x-h-table-row>
        <td x-h-table-head>Onion</td>
        <td x-h-table-cell>Vegetable</td>
      </tr>
      <tr x-h-table-row>
        <td x-h-table-head>Apple</td>
        <td x-h-table-cell>Fruit</td>
      </tr>
    </tbody>
  </table>
</div>

Table with inner borders and no container


html
<table x-h-table data-borders="both" data-fixed="true">
  <thead x-h-table-header>
    <tr x-h-table-row>
      <th x-h-table-head scope="col">Item</th>
      <th x-h-table-head scope="col">Type</th>
    </tr>
  </thead>
  <tbody x-h-table-body>
    <tr x-h-table-row>
      <td x-h-table-head>Cucumber</td>
      <td x-h-table-cell>Vegetable</td>
    </tr>
    <tr x-h-table-row>
      <td x-h-table-head>Banana</td>
      <td x-h-table-cell>Fruit</td>
    </tr>
    <tr x-h-table-row>
      <td x-h-table-head>Asparagus</td>
      <td x-h-table-cell>Vegetable</td>
    </tr>
    <tr x-h-table-row>
      <td x-h-table-head>Onion</td>
      <td x-h-table-cell>Vegetable</td>
    </tr>
    <tr x-h-table-row>
      <td x-h-table-head>Apple</td>
      <td x-h-table-cell>Fruit</td>
    </tr>
  </tbody>
</table>