nuxt-x-affiliate
Search Filters
Faceted search filter sidebar with checkbox, radio, and range groups. Two-way bound state, collapsible groups, clear-all support.
Search Filters
The XAFSearchFilters component renders a faceted filter sidebar that pairs with <XAFSearchBar> and <XAFSearchResults>. It supports three filter types — checkbox (multi-select), radio (single-select), and range (numeric min/max) — and exposes a single v-model for the whole filter state.
Components
<XAFSearchFilters />
<script setup lang="ts">
const filters = ref({ brand: [], price: { min: undefined, max: undefined } })
</script>
<XAFSearchFilters
v-model="filters"
title="Filter products"
:filters="[
{
id: 'brand',
label: 'Brand',
type: 'checkbox',
options: [
{ value: 'amazon', label: 'Amazon', count: 124 },
{ value: 'walmart', label: 'Walmart', count: 89 },
{ value: 'target', label: 'Target', count: 56 },
],
},
{
id: 'price',
label: 'Price',
type: 'range',
range: { min: 0, max: 500, step: 10, unit: 'USD' },
},
]"
/>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
filters | SearchFilter[] | required | Filter group definitions. Each filter has an id, label, optional type ('checkbox' / 'radio' / 'range'), options for choice groups, or range for numeric. |
modelValue | SearchFiltersState | required | Two-way bound filter state. Keyed by filter id. |
title | string | 'Filter' | Section title shown above the filter groups |
showClear | boolean | true | Show a "Clear all" button when any filter is active |
collapsible | boolean | false | Collapse each group by default (mobile-friendly) |
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue | SearchFiltersState | Emitted when any filter changes. Use with v-model. |
Filter state shape
The modelValue is a Record<string, T> keyed by each filter's id:
type SearchFiltersState = Record<
string,
string[] | // checkbox: selected values
string | // radio: selected value
{ min?: number; max?: number } | // range: bounds
undefined // cleared
>
Usage
With <XAFSearchResults>
<script setup lang="ts">
const filters = ref({ brand: [], price: { min: undefined, max: undefined } as { min?: number; max?: number } })
// Reactive query — refetch when filters change.
const results = computed(() => applyFilters(allProducts, filters.value))
</script>
<template>
<div class="grid grid-cols-[280px_1fr] gap-6">
<XAFSearchFilters v-model="filters" :filters="filterDefs" />
<XAFSearchResults :results="results" />
</div>
</template>
With <XAFPagination>
<XAFPagination
:current-page="page"
:total-pages="Math.ceil(results.length / pageSize)"
base-url="/search"
/>
Collapsible (mobile)
<XAFSearchFilters v-model="filters" :filters="filterDefs" collapsible />
Tips
- The component is purely presentational — apply the filters to your data on the consuming side.
- Use
counton checkbox/radio options to show how many items match each filter (great UX signal). - Range filters persist as
{ min, max }so consumers can render "Under $50" labels or similar UI even when only one bound is set.
AI Context
component: XAFSearchFilters
package: "@xenterprises/nuxt-x-affiliate"
use-when: Faceted search filter sidebar for product/review/content discovery
