Pagination
Laravel's pagination feature allows you to query a subset of data and provides your users with the ability to navigate between pages of those results.
Because Laravel's paginator was designed for static applications, in a non-Livewire app, each page navigation triggers a full browser visit to a new URL containing the desired page (?page=2
).
However, when you use pagination inside a Livewire component, users can navigate between pages while remaining on the same page. Livewire will handle everything behind the scenes, including updating the URL query string with the current page.
Basic usage
Below is the most basic example of using pagination inside a ShowPosts
component to only show ten posts at a time:
WithPagination
trait
To take advantage of Livewire's pagination features, each component containing pagination must use the Livewire\WithPagination
trait.
<?php namespace App\Livewire; use Livewire\WithPagination;use Livewire\Component;use App\Models\Post; class ShowPosts extends Component{ use WithPagination; public function render() { return view('show-posts', [ 'posts' => Post::paginate(10), ]); }}
<div> <div> @foreach ($posts as $post) <!-- ... --> @endforeach </div> {{ $posts->links() }}</div>
As you can see, in addition to limiting the number of posts shown via the Post::paginate()
method, we will also use $posts->links()
to render page navigation links.
For more information on pagination using Laravel, check out Laravel's comprehensive pagination documentation.
Disabling URL query string tracking
By default, Livewire's paginator tracks the current page in the browser URL's query string like so: ?page=2
.
If you wish to still use Livewire's pagination utility, but disable query string tracking, you can do so using the WithoutUrlPagination
trait:
use Livewire\WithoutUrlPagination;use Livewire\WithPagination;use Livewire\Component; class ShowPosts extends Component{ use WithPagination, WithoutUrlPagination; // ...}
Now, pagination will work as expected, but the current page won't show up in the query string. This also means the current page won't be persisted across page changes.
Customizing scroll behavior
By default, Livewire's paginator scrolls to the top of the page after every page change.
You can disable this behavior by passing false
to the scrollTo
parameter of the links()
method like so:
{{ $posts->links(data: ['scrollTo' => false]) }}
Alternatively, you can provide any CSS selector to the scrollTo
parameter, and Livewire will find the nearest element matching that selector and scroll to it after each navigation:
{{ $posts->links(data: ['scrollTo' => '#paginated-posts']) }}
Resetting the page
When sorting or filtering results, it is common to want to reset the page number back to 1
.
For this reason, Livewire provides the $this->resetPage()
method, allowing you to reset the page number from anywhere in your component.
The following component demonstrates using this method to reset the page after the search form is submitted:
<?php namespace App\Livewire; use Livewire\WithPagination;use Livewire\Component;use App\Models\Post; class SearchPosts extends Component{ use WithPagination; public $query = ''; public function search() { $this->resetPage(); } public function render() { return view('show-posts', [ 'posts' => Post::where('title', 'like', '%'.$this->query.'%')->paginate(10), ]); }}
<div> <form wire:submit="search"> <input type="text" wire:model="query"> <button type="submit">Search posts</button> </form> <div> @foreach ($posts as $post) <!-- ... --> @endforeach </div> {{ $posts->links() }}</div>
Now, if a user was on page 5
of the results and then filtered the results further by pressing "Search posts", the page would be reset back to 1
.
Available page navigation methods
In addition to $this->resetPage()
, Livewire provides other useful methods for navigating between pages programmatically from your component:
Method | Description |
---|---|
$this->setPage($page) |
Set the paginator to a specific page number |
$this->resetPage() |
Reset the page back to 1 |
$this->nextPage() |
Go to the next page |
$this->previousPage() |
Go to the previous page |
Multiple paginators
Because both Laravel and Livewire use URL query string parameters to store and track the current page number, if a single page contains multiple paginators, it's important to assign them different names.
To demonstrate the problem more clearly, consider the following ShowClients
component:
use Livewire\WithPagination;use Livewire\Component;use App\Models\Client; class ShowClients extends Component{ use WithPagination; public function render() { return view('show-clients', [ 'clients' => Client::paginate(10), ]); }}
As you can see, the above component contains a paginated set of clients. If a user were to navigate to page 2
of this result set, the URL might look like the following:
http://application.test/?page=2
Suppose the page also contains a ShowInvoices
component that also uses pagination. To independently track each paginator's current page, you need to specify a name for the second paginator like so:
use Livewire\WithPagination;use Livewire\Component;use App\Models\Invoices; class ShowInvoices extends Component{ use WithPagination; public function render() { return view('show-invoices', [ 'invoices' => Invoice::paginate(10, pageName: 'invoices-page'), ]); }}
Now, because of the pageName
parameter that has been added to the paginate
method, when a user visits page 2
of the invoices, the URL will contain the following:
https://application.test/customers?page=2&invoices-page=2
When using Livewire's page navigation methods on a named paginator, you must provide the page name as an additional parameter:
$this->setPage(2, pageName: 'invoices-page'); $this->resetPage(pageName: 'invoices-page'); $this->nextPage(pageName: 'invoices-page'); $this->previousPage(pageName: 'invoices-page');
Hooking into page updates
Livewire allows you to execute code before and after a page is updated by defining either of the following methods inside your component:
use Livewire\WithPagination; class ShowPosts extends Component{ use WithPagination; public function updatingPage($page) { // Runs before the page is updated for this component... } public function updatedPage($page) { // Runs after the page is updated for this component... } public function render() { return view('show-posts', [ 'posts' => Post::paginate(10), ]); }}
Named paginator hooks
The previous hooks only apply to the default paginator. If you are using a named paginator, you must define the methods using the paginator's name.
For example, below is an example of what a hook for a paginator named invoices-page
would look like:
public function updatingInvoicesPage($page){ //}
General paginator hooks
If you prefer to not reference the paginator name in the hook method name, you can use the more generic alternatives and simply receive the $pageName
as a second argument to the hook method:
public function updatingPaginators($page, $pageName){ // Runs before the page is updated for this component...} public function updatedPaginators($page, $pageName){ // Runs after the page is updated for this component...}
Using the simple theme
You can use Laravel's simplePaginate()
method instead of paginate()
for added speed and simplicity.
When paginating results using this method, only next and previous navigation links will be shown to the user instead of individual links for each page number:
public function render(){ return view('show-posts', [ 'posts' => Post::simplePaginate(10), ]);}
For more information on simple pagination, check out Laravel's "simplePaginator" documentation.
Using cursor pagination
Livewire also supports using Laravel's cursor pagination — a faster pagination method useful in large datasets:
public function render(){ return view('show-posts', [ 'posts' => Post::cursorPaginate(10), ]);}
By using cursorPaginate()
instead of paginate()
or simplePaginate()
, the query string in your application's URL will store an encoded cursor instead of a standard page number. For example:
https://example.com/posts?cursor=eyJpZCI6MTUsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0
For more information on cursor pagination, check out Laravel's cursor pagination documentation.
Using Bootstrap instead of Tailwind
If you are using Bootstrap instead of Tailwind as your application's CSS framework, you can configure Livewire to use Bootstrap styled pagination views instead of the default Tailwind views.
To accomplish this, set the pagination_theme
configuration value in your application's config/livewire.php
file:
'pagination_theme' => 'bootstrap',
Before customizing the pagination theme, you must first publish Livewire's configuration file to your application's /config
directory by running the following command:
php artisan livewire:publish --config
Modifying the default pagination views
If you want to modify Livewire's pagination views to fit your application's style, you can do so by publishing them using the following command:
php artisan livewire:publish --pagination
After running this command, the following four files will be inserted into the resources/views/vendor/livewire
directory:
View file name | Description |
---|---|
tailwind.blade.php |
The standard Tailwind pagination theme |
tailwind-simple.blade.php |
The simple Tailwind pagination theme |
bootstrap.blade.php |
The standard Bootstrap pagination theme |
bootstrap-simple.blade.php |
The simple Bootstrap pagination theme |
Once the files have been published, you have complete control over them. When rendering pagination links using the paginated result's ->links()
method inside your template, Livewire will use these files instead of its own.
Using custom pagination views
If you wish to bypass Livewire's pagination views entirely, you can render your own in one of two ways:
- The
->links()
method in your Blade view - The
paginationView()
orpaginationSimpleView()
method in your component
->links()
Via The first approach is to simply pass your custom pagination Blade view name to the ->links()
method directly:
{{ $posts->links('custom-pagination-links') }}
When rendering the pagination links, Livewire will now look for a view at resources/views/custom-pagination-links.blade.php
.
paginationView()
or paginationSimpleView()
Via The second approach is to declare a paginationView
or paginationSimpleView
method inside your component which returns the name of the view you would like to use:
public function paginationView(){ return 'custom-pagination-links-view';} public function paginationSimpleView(){ return 'custom-simple-pagination-links-view';}
Sample pagination view
Below is an unstyled sample of a simple Livewire pagination view for your reference.
As you can see, you can use Livewire's page navigation helpers like $this->nextPage()
directly inside your template by adding wire:click="nextPage"
to buttons:
<div> @if ($paginator->hasPages()) <nav role="navigation" aria-label="Pagination Navigation"> <span> @if ($paginator->onFirstPage()) <span>Previous</span> @else <button wire:click="previousPage" wire:loading.attr="disabled" rel="prev">Previous</button> @endif </span> <span> @if ($paginator->onLastPage()) <span>Next</span> @else <button wire:click="nextPage" wire:loading.attr="disabled" rel="next">Next</button> @endif </span> </nav> @endif</div>