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(4mo ago)10MITPHPPHP ^8.2CI passing

Since Mar 25Pushed 4mo 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 yesterday

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

34

—

LowBetter than 74% of packages

Maintenance75

Regular maintenance activity

Popularity2

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity47

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

138d 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.

935628.9k2](/packages/mailerlite-laravel-elasticsearch)[jeroen-g/explorer

Next-gen Elasticsearch driver for Laravel Scout.

399693.0k](/packages/jeroen-g-explorer)[tomshaw/electricgrid

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

119.8k](/packages/tomshaw-electricgrid)

PHPackages © 2026

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