Skip to content

Custom Pagination

The built-in pagination shows Previous/Next buttons and a "Showing X to Y results" summary. With full pagination (->paginate()), First/Last buttons and the total count are included. You can replace the pagination controls, the empty state, or both.

Custom Pagination UI

Replace the default pagination controls with your own UI using renderPagination (React) or the #pagination slot (Vue). This is useful when integrating with a design system or when you need a different layout - numbered page buttons, infinite scroll triggers, or a "load more" pattern.

tsx
<InertiaTable
    tableData={servers}
    renderPagination={({ links, meta, onPageChange, isFetching }) => (
        <div className="flex items-center justify-between px-4 py-4 border-t">
            <span className="text-sm text-gray-500">
                Showing {meta.from} to {meta.to}
                {meta.total != null && <> of {meta.total} results</>}
            </span>
            <div className="flex gap-2">
                <button
                    disabled={!links.prev || isFetching}
                    onClick={() => onPageChange(meta.current_page - 1)}
                    className="px-3 py-1.5 border rounded disabled:opacity-50"
                >
                    Previous
                </button>
                <button
                    disabled={!links.next || isFetching}
                    onClick={() => onPageChange(meta.current_page + 1)}
                    className="px-3 py-1.5 border rounded disabled:opacity-50"
                >
                    Next
                </button>
            </div>
        </div>
    )}
/>
template
<InertiaTable :table-data="servers">
    <template #pagination="{ links, meta, onPageChange, isFetching }">
        <div class="flex items-center justify-between px-4 py-4 border-t">
            <span class="text-sm text-gray-500">
                Showing {{ meta.from }} to {{ meta.to }}
                <template v-if="meta.total != null"> of {{ meta.total }} results</template>
            </span>
            <div class="flex gap-2">
                <button
                    :disabled="!links.prev || isFetching"
                    @click="onPageChange(meta.current_page - 1)"
                    class="px-3 py-1.5 border rounded disabled:opacity-50"
                >
                    Previous
                </button>
                <button
                    :disabled="!links.next || isFetching"
                    @click="onPageChange(meta.current_page + 1)"
                    class="px-3 py-1.5 border rounded disabled:opacity-50"
                >
                    Next
                </button>
            </div>
        </div>
    </template>
</InertiaTable>

The render prop (React) or scoped slot (Vue) receives:

tsx
interface PaginationRenderProps {
    links: PaginationLinks;            // { first, last, prev, next } URLs
    meta: PaginationMeta;              // { current_page, from, to, per_page, total?, last_page? }
    onPageChange: (page: number) => void;  // navigate to a page number
    isFetching: boolean;               // true while a navigation is in progress
}

links.first and links.last are only present when using ->paginate() (full pagination). With ->simplePaginate(), only prev and next are available. See Pagination for the difference between the two methods.

Custom Empty State

When the table has no rows, a default "No results found." message is shown. For a simple text change, use the emptyText prop. For a fully custom layout with actions or illustrations, use renderEmpty (React) or the #empty slot (Vue).

tsx
{/* Simple text override */}
<InertiaTable tableData={servers} emptyText="No servers found" />

{/* Fully custom empty state */}
<InertiaTable
    tableData={servers}
    renderEmpty={() => (
        <div className="p-12 text-center">
            <h3 className="text-lg font-medium">No servers yet</h3>
            <p className="mt-1 text-gray-500">Create your first server to get started.</p>
            <button className="mt-4 px-4 py-2 bg-blue-600 text-white rounded-md">
                Create Server
            </button>
        </div>
    )}
/>
template
<!-- Simple text override -->
<InertiaTable :table-data="servers" empty-text="No servers found" />

<!-- Fully custom empty state -->
<InertiaTable :table-data="servers">
    <template #empty>
        <div class="p-12 text-center">
            <h3 class="text-lg font-medium">No servers yet</h3>
            <p class="mt-1 text-gray-500">Create your first server to get started.</p>
            <button class="mt-4 px-4 py-2 bg-blue-600 text-white rounded-md">
                Create Server
            </button>
        </div>
    </template>
</InertiaTable>

Summary

PropWhat it does
renderPagination (React) / #pagination slot (Vue)Replaces the pagination controls
emptyTextChanges the empty state message text
renderEmpty (React) / #empty slot (Vue)Replaces the entire empty state with custom markup