Data Table

Data tables display sets of data across rows and columns. They organize information in a way that’s easy to scan so that users can look for patterns and insights.

Page of
HTML
                        
    <div x-data="table">
        <div class="d-flex justify-content-between mb-3">
            <div>
                <input type="text" class="form-control" placeholder="Search..." x-model="search">
            </div>
        </div>
        <table class="table">
            <thead>
                <tr>
                    <template x-for="column in columns" :key="column.key">
                        <th scope="col" :class="sortColumn === column.key ? 'active' : ''"
                            @click="sort(column.key)">
                            <span x-text="column.name"></span>
                            <span x-show="sortColumn === column.key"
                                :class="sortDirection === 'asc' ? 'fa fa-arrow-up' : 'fa fa-arrow-down'"></span>
                        </th>
                    </template>
                </tr>
            </thead>
            <tbody>
                <template x-for="row in filteredAndSortedData()" :key="row.id">
                    <tr>
                        <td x-text="row.id"></td>
                        <td x-text="row.firstName"></td>
                        <td x-text="row.lastName"></td>
                        <td x-text="row.age"></td>
                        <td x-text="row.birthDate"></td>
                        <td x-text="row.email"></td>
                    </tr>
                </template>
            </tbody>
        </table>
        <div class="d-flex justify-content-between align-items-center mt-3">
            <div>
                <select class="form-select" x-model="limit" @change="changeLimit($event.target.value)">
                    <option value="5">5</option>
                    <option value="10">10</option>
                    <option value="20">20</option>
                </select>
            </div>
            <span>Page <span x-text="page"></span> of <span x-text="totalPages()"></span></span>
            <div>
                <button class="btn btn-secondary" :disabled="page === 1"
                    @click="page--">Previous</button>
                <button class="btn btn-secondary" :disabled="page === totalPages()"
                    @click="page++">Next</button>
            </div>
        </div>
    </div>
                        
                    
JS
                        
    <script>
        document.addEventListener("alpine:init", () => {
            Alpine.data("table", () => ({
                tableData: [],
                columns: [
                    { name: "ID", key: "id" },
                    { name: "Firstname", key: "firstName" },
                    { name: "Lastname", key: "lastName" },
                    { name: "Age", key: "age" },
                    { name: "Start date", key: "birthDate" },
                    { name: "Email", key: "email" }
                ],
                search: "",
                sortColumn: "id",
                sortDirection: "asc",
                page: 1,
                limit: 5, // Number of rows per page

                init() {
                    this.fetchData();
                },

                fetchData() {
                    fetch('https://dummyjson.com/users')
                        .then(res => res.json())
                        .then(data => {
                            this.tableData = data.users;
                        });
                },

                sort(column) {
                    if (this.sortColumn === column) {
                        this.sortDirection = this.sortDirection === "asc" ? "desc" : "asc";
                    } else {
                        this.sortColumn = column;
                        this.sortDirection = "asc";
                    }
                },

                changeLimit(limit) {
                    this.limit = limit;
                    this.page = 1;
                },

                filteredAndSortedData() {
                    let data = this.tableData;

                    // Search Filter
                    if (this.search) {
                        data = data.filter(row =>
                            Object.values(row).some(value =>
                                String(value).toLowerCase().includes(this.search.toLowerCase())
                            )
                        );
                    }

                    // Sorting
                    data.sort((a, b) => {
                        let valA = a[this.sortColumn];
                        let valB = b[this.sortColumn];
                        if (typeof valA === "string") valA = valA.toLowerCase();
                        if (typeof valB === "string") valB = valB.toLowerCase();

                        if (this.sortDirection === "asc") {
                            return valA > valB ? 1 : -1;
                        } else {
                            return valA < valB ? 1 : -1;
                        }
                    });

                    // Pagination
                    const start = (this.page - 1) * this.limit;
                    const end = start + this.limit;
                    return data.slice(start, end);
                },

                totalPages() {
                    return Math.ceil(this.tableData.length / this.limit);
                },
            }));
        });
    </script>