Pagination
A full-featured pagination system that integrates Laravel's paginator with LiVue. Supports both server-rendered Blade links and fully reactive Vue-driven pagination UI.
Overview
LiVue provides the UsePagination trait to add pagination capabilities to any component. It handles page tracking, URL synchronization, navigation methods, and exposes reactive pagination metadata to the Vue template via a composable.
Blade Approach
Server-rendered pagination links with $this->links(). Zero JavaScript required.
Vue Approach
Build custom pagination UI with reactive data and navigation actions from the pagination composable.
URL Sync
Current page is automatically synced with the URL query string, so pagination state is bookmarkable and shareable.
Basic Setup
Add the UsePagination trait to your component and register usePagination in the $composables array:
<?php
namespace App\LiVue;
use LiVue\Component;
use LiVue\Features\SupportPagination\UsePagination;
class UserList extends Component
{
use UsePagination;
protected array $composables = ['usePagination'];
public function render(): string
{
return 'livue.user-list';
}
}
Blade Template
Use $this->paginate() to paginate an Eloquent query and $this->links() to render the pagination links:
<div>
@php $users = $this->paginate(User::query(), 10) @endphp
@foreach ($users as $user)
<div class="p-4 border-b">
<p>{{ $user->name }}</p>
<p class="text-sm text-gray-500">{{ $user->email }}</p>
</div>
@endforeach
<div class="mt-4">
{{ $this->links() }}
</div>
</div>
Tip — The paginate() method accepts any Eloquent Builder or Relation instance. If you already have a paginator from elsewhere, use $this->setPaginator($paginator) instead.
Vue Pagination
When you register usePagination as a composable, all pagination data and navigation actions become available in your Vue template under the pagination namespace. This lets you build fully custom pagination UI.
<div>
@php $users = $this->paginate(User::query(), 10) @endphp
@foreach ($users as $user)
<div class="p-4 border-b">
<p>{{ $user->name }}</p>
</div>
@endforeach
<!-- Custom Vue pagination UI -->
<div class="flex items-center justify-between mt-4">
<button @click="pagination.previousPage()"
:disabled="pagination.onFirstPage">
Previous
</button>
<span>
Page {{ pagination.page }} of {{ pagination.lastPage }}
<small>({{ pagination.total }} items)</small>
</span>
<button @click="pagination.nextPage()"
:disabled="!pagination.hasMorePages">
Next
</button>
</div>
</div>
Reactive Data
The following properties are available on the pagination object and update reactively after every server round-trip:
| Property | Type | Description |
|---|---|---|
pagination.page |
int | Current page number |
pagination.total |
int | Total number of items across all pages |
pagination.perPage |
int | Number of items per page |
pagination.lastPage |
int | Last page number (total pages) |
pagination.hasPages |
bool | Whether there are multiple pages (total > perPage) |
pagination.onFirstPage |
bool | Whether the current page is the first page |
pagination.hasMorePages |
bool | Whether there are more pages after the current one |
Navigation Actions
Call these methods from your Vue template to navigate between pages. Each triggers a server round-trip to fetch the new page data:
| Action | Description |
|---|---|
pagination.nextPage() |
Go to the next page |
pagination.previousPage() |
Go to the previous page |
pagination.setPage(n) |
Jump to a specific page number |
pagination.resetPage() |
Reset to page 1 |
pagination.firstPage() |
Go to the first page |
Tip — You can mix both approaches: use $this->links() for standard pagination links and pagination.total in Vue to display "Showing X of Y results".
Configuration
The default pagination view is configured globally via the pagination key in config/livue.php:
'pagination' => 'default',
Supported Values
| Value | View | Description |
|---|---|---|
'default' |
livue::pagination.tailwind |
Full pagination with page numbers, styled with Tailwind CSS |
'simple' |
livue::pagination.simple |
Minimal Previous / Next buttons only |
'your.view.path' |
Custom | Any Laravel view path for fully custom pagination markup |
Per-Component Override
Override the pagination view for a specific component by defining the paginationView() or paginationSimpleView() method:
class UserList extends Component
{
use UsePagination;
public function paginationView(): string
{
return 'components.my-pagination';
}
public function paginationSimpleView(): string
{
return 'components.my-simple-pagination';
}
}
Note — LiVue automatically overrides Laravel's default pagination views only when rendering components that use UsePagination. After the component finishes rendering, the original Laravel defaults are restored so other parts of your application are not affected.
PHP Methods
The UsePagination trait adds the following methods to your component:
| Method | Returns | Description |
|---|---|---|
paginate($query, $perPage) |
LengthAwarePaginator | Paginates an Eloquent query and stores the paginator internally |
setPaginator($paginator) |
Paginator | Stores an existing paginator (useful when you build queries outside the template) |
links() |
Htmlable | Renders the pagination view using the internal paginator |
setPage($page) |
void | Sets the current page number |
resetPage() |
void | Resets to page 1 |
nextPage() |
void | Advances to the next page |
previousPage() |
void | Goes back to the previous page |
firstPage() |
void | Jumps to the first page |
lastPage($lastPage) |
void | Jumps to the last page (requires total pages count) |
Using setPaginator()
When you build your paginator in a PHP method (e.g., mount() or a custom action) instead of in the Blade template, use setPaginator() to make it available to links() and the composable:
class ProductCatalog extends Component
{
use UsePagination;
protected array $composables = ['usePagination'];
public string $category = 'all';
public function render(): string
{
$query = Product::query();
if ($this->category !== 'all') {
$query->where('category', $this->category);
}
$this->setPaginator(
$query->paginate(12)
);
return 'livue.product-catalog';
}
}
URL Synchronization
The UsePagination trait automatically syncs the current page with the URL query string using the #[Url] attribute. This means:
-
‣
The URL updates to
?page=2as users navigate between pages -
‣
Page 1 uses a clean URL (no
?page=1) thanks to#[Url(except: 1)] - ‣ Users can bookmark or share specific pages directly
- ‣ Browser back/forward navigation works correctly
SPA Navigation
Blade-rendered pagination links automatically include v-navigate, so clicking page numbers uses LiVue's SPA navigation instead of a full page reload. This provides instant page transitions while keeping the URL updated.
Resetting on Filter Change
When the user changes a filter (e.g., category, search query), you should reset pagination to page 1 to avoid showing an empty page:
public function updatedCategory(): void
{
$this->resetPage();
}
Tip — The updated{Property} lifecycle hook fires whenever a public property changes. Calling resetPage() there ensures the user always sees page 1 after changing filters.