This article explores creating dynamic tables using Alpine JS, a lightweight JavaScript framework. We'll break down the process into three sections: header, body, and footer, focusing on both basic and complex scenarios.
Setting Up:
- HTML Structure: We begin with a basic HTML element () with the x-data directive attached. This directive binds reactive data to the element.
- JavaScript Data: We define an empty JavaScript object (data) outside the HTML to hold our table data.
- We use the thead element for the header.
- The
x-for
directive iterates over table.customHeader data, creating rows and columns dynamically. - Complex headers can leverage colspan and rowspan attributes (defined in
col.attr
) to merge cells. - Content within each cell is displayed using
x-html
and bound to thecol.title
property. - The
tbody
element holds the table's data rows. - We iterate through table.data using
x-for
. - Each row houses cells (
<td>
) populated with data from corresponding object properties usingx-text
. - The
tfoot
element defines the footer. - Similar to the header, it uses
x-for
to iterate throughtable.customFooter
data. - However, the footer can display dynamic values by referencing properties within
table.footerData
usingx-html
. - Styling is achieved using CSS classes defined within the
col.class
anddata.class
properties. - The provided link offers a full working demo for further exploration.
- Demo: https://framework.fuwafuwa.web.id/examples/simple-table
- Explanation: https://framework.fuwafuwa.web.id/docs/simple-table.html#simple-table
The initial code is below:
<div x-data="data">
</div>
<script>
let data = {
}
</script>
Header
<thead class="sticky top-0 z-10 text-gray-700 bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<template x-for="row in table.customHeader">
<tr>
<template x-for="col in row">
<th class="px-4 font-semibold text-left border-b py-1.5"
x-init="col.attr && Object.keys(col.attr).forEach(e => $el.setAttribute(e, col.attr[e]))">
<div class="flex items-center justify-center">
<span x-html="col.title" class="whitespace-nowrap"></span>
</div>
</th>
</template>
</tr>
</template>
</thead>
let data = {
table: {
customHeader: [
[
{ title: 'City', attr: { rowspan: 2 }, class: 'border-r border-t' },
{ title: 'Clothes', attr: { colspan: 3 }, class: 'border-r border-t' },
{ title: 'Accessories', attr: { colspan: 2 }, class: 'border-t' }
],
[
{ title: 'Trousers', class: 'border-r' },
{ title: 'Skirts', class: 'border-r' },
{ title: 'Dresses', class: 'border-r' },
{ title: 'Bracelets', class: 'border-r' },
{ title: 'Rings' },
]
],
}
}
Body
<tbody>
<template x-for="(row, idx) in table.data">
<tr class="border-b dark:border-gray-700">
<template x-for="(col, icol) in row.columns">
<td x-bind:class="{ [col.class]: !!col.class }" class="px-3 border-b border-gray-200">
<div x-text="col.text"></div>
</td>
</template>
</tr>
</template>
</tbody>
And this is the data we want to show:
data: [
{ "city": "Mandalay", "trousers": 79, "skirts": 16, "dresses": 14, "bracelets": 69, "rings": 99 },
{ "city": "George Town", "trousers": 68, "skirts": 24, "dresses": 90, "bracelets": 96, "rings": 48 },
{ "city": "Gent", "trousers": 26, "skirts": 60, "dresses": 67, "bracelets": 5, "rings": 43 },
{ "city": "Mombasa", "trousers": 34, "skirts": 62, "dresses": 18, "bracelets": 75, "rings": 78 },
{ "city": "Lyon", "trousers": 13, "skirts": 33, "dresses": 12, "bracelets": 0, "rings": 17 },
{ "city": "Vancouver", "trousers": 82, "skirts": 91, "dresses": 18, "bracelets": 96, "rings": 72 },
{ "city": "Cairn", "trousers": 64, "skirts": 43, "dresses": 14, "bracelets": 95, "rings": 55 },
]
Footer
<tfoot class="sticky bg-gray-100 -bottom-1">
<template x-for="row in table.customFooter">
<tr>
<template x-for="col in row">
<td class="px-3 border-b border-gray-200"
x-init="col.attr && Object.keys(col.attr).forEach(e => $el.setAttribute(e, col.attr[e]))">
<div x-html="table.footerData[col.name)">
</div>
</td>
</template>
</tr>
</template>
</tfoot>
customFooter: [
[
{ value: 'Total', class: 'font-bold border-r text-center', attr: { rowspan: 2 } },
{ name: 'total-trousers', class: 'text-right border-r' },
{ name: 'total-skirts', class: 'text-right border-r', },
{ name: 'total-dresses', class: 'text-right border-r' },
{ name: 'total-bracelets', class: 'text-right border-r' },
{ name: 'total-rings', class: 'text-right' },
],
[
{ name: 'total-clothes', class: 'text-center border-r', attr: { colspan: 3 } },
{ name: 'total-accessories', class: 'text-center', attr: { colspan: 2 } },
],
],
Example Data:
We demonstrate the table's functionality with sample data containing city names and various clothing items.
Additional Notes:
External links
Conclusion:
This breakdown showcases how Alpine JS empowers us to create dynamic tables with flexible headers, bodies, and footers. This approach simplifies table creation and management, especially for scenarios with frequently changing data.
Top comments (0)