PHPackages                             nazalas/laravel-persistent-table-filters - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Search &amp; Filtering](/categories/search)
4. /
5. nazalas/laravel-persistent-table-filters

ActiveLibrary[Search &amp; Filtering](/categories/search)

nazalas/laravel-persistent-table-filters
========================================

Persist and restore table filter, sort, and search state per user in Laravel applications.

v1.0.0(3mo ago)00MITPHPPHP ^8.2CI passing

Since Mar 25Pushed 3mo agoCompare

[ Source](https://github.com/Nazalas/laravel-persistent-table-filters)[ Packagist](https://packagist.org/packages/nazalas/laravel-persistent-table-filters)[ Docs](https://github.com/Nazalas/laravel-persistent-table-filters)[ RSS](/packages/nazalas-laravel-persistent-table-filters/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependencies (4)Versions (2)Used By (0)

Laravel Persistent Table Filters
================================

[](#laravel-persistent-table-filters)

[![Latest Version on Packagist](https://camo.githubusercontent.com/7309e1976f6375c5f101a78831e80e72de9b219612c5f699c896f906fee8ac45/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6e617a616c61732f6c61726176656c2d70657273697374656e742d7461626c652d66696c746572732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/nazalas/laravel-persistent-table-filters)[![Tests](https://github.com/Nazalas/laravel-persistent-table-filters/actions/workflows/tests.yml/badge.svg)](https://github.com/Nazalas/laravel-persistent-table-filters/actions/workflows/tests.yml)[![License](https://camo.githubusercontent.com/2bab08db12b6a89a8c99bb31b8177dde81c584ae7d96734083978f7959fc2845/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6e617a616c61732f6c61726176656c2d70657273697374656e742d7461626c652d66696c746572732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/nazalas/laravel-persistent-table-filters)

Automatically persist and restore table filter, sort, and search state per user in Laravel applications. Works great with Livewire.

The Problem
-----------

[](#the-problem)

Users refine a table — searching, sorting, filtering — then navigate away or refresh. Everything resets. This package silently saves filter state as users interact and restores it automatically on the next visit. Optionally, users can also save named filter presets and switch between them.

Features
--------

[](#features)

- **Auto-persist** — silently saves filter state on every change; restores it on mount with no user interaction
- **Named presets** — users can save, label, and reload specific filter configurations
- **Default preset** — mark one named preset as the default fallback
- **Per-user, per-resource** — state is scoped to the authenticated user and a resource key you define
- **Opt-out** — set `$autoSaveFilters = false` on any component to disable auto-persist

Installation
------------

[](#installation)

```
composer require nazalas/laravel-persistent-table-filters
```

Publish and run the migration:

```
php artisan vendor:publish --tag="persistent-table-filters-migrations"
php artisan migrate
```

Optionally publish the config:

```
php artisan vendor:publish --tag="persistent-table-filters-config"
```

Usage
-----

[](#usage)

### Livewire Component

[](#livewire-component)

Add the `HasPersistentFilters` trait, define a resource key and which properties make up your filter state:

```
use Nazalas\PersistentTableFilters\Traits\HasPersistentFilters;

class CampaignIndex extends Component
{
    use HasPersistentFilters;

    // Unique key for this table — scopes saved state per resource
    protected string $filterResource = 'campaigns';

    // Which component properties make up the filter state
    protected array $filterKeys = ['search', 'sort_by', 'sort_dir', 'status'];

    public string $search = '';
    public string $sort_by = 'name';
    public string $sort_dir = 'asc';
    public string $status = '';

    public function mount(): void
    {
        // Restore last state (auto-persisted or named default)
        $this->restoreFilters();
    }

    public function updatedSearch(): void
    {
        $this->resetPage();
        $this->persistFilters(); // silently save on every change
    }

    public function updatedStatus(): void
    {
        $this->resetPage();
        $this->persistFilters();
    }
}
```

That's the core usage. Filters now survive page refreshes automatically with no user action needed.

### Disabling Auto-Persist

[](#disabling-auto-persist)

Set `$autoSaveFilters = false` on any component to prevent `persistFilters()` from writing to the database:

```
protected bool $autoSaveFilters = false;
```

### Clearing Persisted State

[](#clearing-persisted-state)

```
$this->clearPersistedFilters();
```

Wipes the auto-persisted record for the current user + resource. The next page load will start fresh (or fall back to a named default if one exists).

---

Named Presets (Optional)
------------------------

[](#named-presets-optional)

On top of auto-persist, users can save and reload named filter configurations.

### Saving a Preset

[](#saving-a-preset)

```
// Save current state with a label
$filter = $this->saveFilter('Active campaigns');

// Save and mark as the default fallback
$filter = $this->saveFilter('My default view', setAsDefault: true);
```

### Loading a Preset

[](#loading-a-preset)

```
$this->loadFilter($filterId);
// Also updates the auto-persisted state
```

### Deleting a Preset

[](#deleting-a-preset)

```
$this->deleteFilter($filterId);
```

### Listing Presets

[](#listing-presets)

```
$filters = $this->getSavedFilters(); // Collection of TableFilter — excludes auto records
```

### Example Blade UI for Presets

[](#example-blade-ui-for-presets)

```

    @if($this->getSavedFilters()->count())

            Load saved filter...
            @foreach($this->getSavedFilters() as $filter)

                    {{ $filter->label }}{{ $filter->is_default ? ' ★' : '' }}

            @endforeach

    @endif

        Save

    Save current filters

```

---

How Restore Priority Works
--------------------------

[](#how-restore-priority-works)

`restoreFilters()` follows this order:

1. **Auto-persisted state** — the last state saved by `persistFilters()` (if any)
2. **Named default** — a named preset marked `is_default = true` (if no auto state)
3. **Component defaults** — the property values you declared in the class (if neither exists)

---

Using Without Livewire
----------------------

[](#using-without-livewire)

The `TableFilter` model and scopes work independently of Livewire:

```
use Nazalas\PersistentTableFilters\Models\TableFilter;

// Save state manually
TableFilter::updateOrCreate(
    ['user_id' => auth()->id(), 'resource' => 'campaigns', 'is_auto' => true],
    ['label' => null, 'filters' => $request->only(['search', 'status', 'sort_by'])]
);

// Restore state
$state = TableFilter::forCurrentUser()
    ->forResource('campaigns')
    ->where('is_auto', true)
    ->first()
    ?->filters ?? [];
```

---

Configuration
-------------

[](#configuration)

```
// config/persistent-table-filters.php

return [
    'table_name'                => 'table_filters',
    'user_model'                => \App\Models\User::class,
    'max_per_user_per_resource' => 20,  // named presets only; null = no limit
];
```

---

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

See [CHANGELOG.md](CHANGELOG.md).

License
-------

[](#license)

MIT. See [LICENSE](LICENSE).

###  Health Score

35

—

LowBetter than 77% of packages

Maintenance82

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

93d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/5007099?v=4)[Nazalas](/maintainers/Nazalas)[@Nazalas](https://github.com/Nazalas)

---

Tags

searchlaravelsortlivewiretablefilterspersistent

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/nazalas-laravel-persistent-table-filters/health.svg)

```
[![Health](https://phpackages.com/badges/nazalas-laravel-persistent-table-filters/health.svg)](https://phpackages.com/packages/nazalas-laravel-persistent-table-filters)
```

###  Alternatives

[mailerlite/laravel-elasticsearch

An easy way to use the official PHP ElasticSearch client in your Laravel applications.

935572.3k2](/packages/mailerlite-laravel-elasticsearch)[tomshaw/electricgrid

A feature-rich Livewire package designed for projects that require dynamic, interactive data tables.

119.2k](/packages/tomshaw-electricgrid)[kirschbaum-development/livewire-filters

Livewire Filters is a series of Livewire components that provide you with the tools to do live filtering of your data from your own Livewire components.

164.1k](/packages/kirschbaum-development-livewire-filters)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
