Neura UI

Composable Laravel UI
By Neura UI
Home

Filters

Composable filter chips with field types, operators, and value editors — ideal for toolbars, tables, and data views.

Basic Usage

Pass a list of filterable fields. Users add filters from the menu; each active filter renders as a chip with a field label, an operator dropdown, a value editor, and a remove button:
Preview
no results found
Status
Priority
Assignee
<neura::filters
    :fields="[
        [
            'key' => 'status',
            'label' => 'Status',
            'icon' => 'signal',
            'type' => 'select',
            'options' => [
                ['value' => 'active', 'label' => 'Active', 'color' => '#22c55e'],
                ['value' => 'inactive', 'label' => 'Inactive', 'color' => '#a1a1aa'],
            ],
        ],
        [
            'key' => 'priority',
            'label' => 'Priority',
            'type' => 'multiselect',
            'options' => [
                ['value' => 'low', 'label' => 'Low'],
                ['value' => 'high', 'label' => 'High'],
            ],
        ],
        ['key' => 'name', 'label' => 'Name', 'type' => 'text'],
    ]"
    :value="[
        ['field' => 'priority', 'operator' => 'is_any_of', 'values' => ['low', 'medium']],
    ]"
/>

Field Types

Three field types are supported. Select and multiselect use an options list; text uses a free-form input. Choosing is empty or is not empty hides the value editor:
Preview
no results found
Status
Priority
Assignee
<neura::filters
    :fields="$fields"
    :value="[
        ['field' => 'status', 'operator' => 'is', 'values' => ['active']],
        ['field' => 'name', 'operator' => 'contains', 'values' => ['neura']],
        ['field' => 'assignee', 'operator' => 'not_empty', 'values' => []],
    ]"
/>

Default operators by type

Property Type Default Description
select is, is_not, empty, not_empty Default: is
multiselect is_any_of, is_not_any_of, includes_all, excludes_all, empty, not_empty Default: is_any_of
text contains, not_contains, starts_with, ends_with, is, empty, not_empty Default: contains

Option Colors and Icons

Options can include a color (shown as a dot) or an icon (Heroicon name). Colors also appear on the chip when a single option is selected:
Preview
no results found
Status
<neura::filters
    :fields="[
        [
            'key' => 'status',
            'label' => 'Status',
            'type' => 'select',
            'options' => [
                ['value' => 'active', 'label' => 'Active', 'color' => '#22c55e'],
                ['value' => 'pending', 'label' => 'Pending', 'color' => '#f59e0b'],
            ],
        ],
    ]"
/>

Custom Trigger

Replace the default outline button with the trigger slot:
Preview
no results found
Status
Priority
Assignee
<neura::filters :fields="$fields">
    <x-slot:trigger>
        <neura::button variant="primary" size="sm" icon="plus">
            Add filter
        </neura::button>
    </x-slot:trigger>
</neura::filters>

Single Filter per Field

With :allow-multiple="false" , fields already in use disappear from the add menu. Hide the menu search with :show-search="false" :
Preview
no results found
Status
Priority
Assignee
<neura::filters
    :fields="$fields"
    :allow-multiple="false"
    :show-search="false"
/>

Custom Operators

Override the operator list (and the default) per field:
Preview
no results found
<neura::filters
    :fields="[
        [
            'key' => 'title',
            'label' => 'Title',
            'type' => 'text',
            'operators' => ['contains', 'is', 'starts_with'],
            'defaultOperator' => 'starts_with',
        ],
    ]"
/>

Listening for Changes

Every mutation dispatches filters-changed and syncs with wire:model / x-model . Each filter is { id, field, operator, values } :
Preview
no results found
Status
Priority
Assignee

<div x-on:filters-changed="console.log($event.detail.filters)">
    <neura::filters :fields="$fields" />
</div>


<neura::filters :fields="$fields" wire:model.live="filters" />


<neura::filters :fields="$fields" name="filters" />

Livewire example

PHP
class Inbox extends Component
{
    public array $filters = [];

    public function getFilteredQuery()
    {
        $query = Message::query();

        foreach ($this->filters as $filter) {
            // $filter['field'], $filter['operator'], $filter['values']
        }

        return $query;
    }
}

Disabled State

Disable all interactions with :disabled="true" :
Preview
no results found
Status
Priority
Assignee
<neura::filters :fields="$fields" :disabled="true" />

Props

Property Type Default Description
fields array [] Required. Filterable field configurations
value array [] Initial filters: ['field' =>, 'operator' =>, 'values' => []]
label string translated Label of the default trigger button
name string|null auto Hidden input name (from wire:model / x-model when omitted)
showSearch boolean true Show the field search input in the add-filter menu
allowMultiple boolean true Allow several active filters on the same field
showClear boolean true Show the Clear all button when filters are active
disabled boolean false Disable all interactions
trigger (slot) slot Custom element that opens the add-filter menu

Field Configuration

Property Type Default Description
key string Required. Unique field identifier
label string title of key Human-readable label
type string select select , multiselect , or text
icon string|null null Heroicon shown next to the field label
options array [] ['value' =>, 'label' =>, 'color' => ?, 'icon' => ?] for select / multiselect
operators array by type Override the operator list for this field
defaultOperator string by type Operator applied when the filter is created
placeholder string|null null Placeholder of the text value input
searchable boolean true Show a search input above the options list

Best Practices

Do

  • Keep field keys stable — they are persisted in filter payloads
  • Use select for enums, multiselect for tags
  • Bind with wire:model.live when filtering Livewire queries
  • Provide colors for status-like options to improve scanability

Don't

  • Don't put dozens of fields in one menu — split into groups or sideovers
  • Don't use multiselect without handling array values in your query
  • Don't change field keys between deploys if filters are stored in URLs or prefs