8.9k

Filter

PreviousNext

An e-commerce filter component with multi-select, search, grouping, and reset functionality.

<script setup lang="ts">
import { ref } from 'vue'
import {
  Filter,
  FilterContent,
  FilterEmpty,
  FilterGroup,
  FilterIndicator,
  FilterInput,
  FilterItem,
  FilterList,
  FilterReset,
  FilterSeparator,
  FilterTrigger,
} from '@/components/ui/filter'

const selectedColors = ref<string[]>([])

const colorOptions = [
  { option: 'Red', count: 24 },
  { option: 'Blue', count: 18 },
  { option: 'Green', count: 12 },
  { option: 'Black', count: 42 },
  { option: 'White', count: 36 },
]

const sizeOptions = [
  { option: 'XS', count: 8 },
  { option: 'S', count: 15 },
  { option: 'M', count: 22 },
  { option: 'L', count: 19 },
  { option: 'XL', count: 11 },
]
</script>

<template>
  <div class="flex w-full max-w-xs flex-col gap-4">
    <Filter v-model="selectedColors" multiple>
      <FilterTrigger>Product Filters</FilterTrigger>
      <FilterContent>
        <FilterInput placeholder="Search filters..." />
        <FilterList>
          <FilterEmpty>No filters found.</FilterEmpty>

          <FilterGroup heading="Colors">
            <FilterItem
              v-for="color in colorOptions"
              :key="color.option"
              :value="color.option"
              :option="color"
            >
              <FilterIndicator />
            </FilterItem>
          </FilterGroup>

          <FilterSeparator />

          <FilterGroup heading="Sizes">
            <FilterItem
              v-for="size in sizeOptions"
              :key="size.option"
              :value="size.option"
              :option="size"
            >
              <FilterIndicator />
            </FilterItem>
          </FilterGroup>
        </FilterList>

        <FilterReset>
          Reset Filters
        </FilterReset>
      </FilterContent>
    </Filter>

    <div v-if="selectedColors.length" class="text-sm text-muted-foreground">
      Selected: {{ selectedColors.join(', ') }}
    </div>
  </div>
</template>

Installation

pnpm dlx @frontic/ui add filter

Usage

<script setup lang="ts">
import { ref } from 'vue'
import {
  Filter,
  FilterContent,
  FilterEmpty,
  FilterGroup,
  FilterIndicator,
  FilterInput,
  FilterItem,
  FilterList,
  FilterReset,
  FilterSeparator,
  FilterTrigger,
} from '@/components/ui/filter'

const selected = ref<string[]>([])
</script>

<template>
  <Filter v-model="selected" multiple>
    <FilterInput placeholder="Search..." />
    <FilterContent>
      <FilterList>
        <FilterEmpty>No results found.</FilterEmpty>
        <FilterGroup heading="Category">
          <FilterItem value="option1" :option="{ option: 'Option 1', count: 10 }">
            <FilterIndicator />
          </FilterItem>
        </FilterGroup>
      </FilterList>
    </FilterContent>
    <FilterReset>Reset</FilterReset>
  </Filter>
</template>

Anatomy

The Filter component is built from multiple sub-components:

  • Filter - Root component that wraps the combobox
  • FilterInput - Search input with icon
  • FilterContent - Animated content container
  • FilterList - Scrollable viewport for options
  • FilterGroup - Groups options with an optional heading
  • FilterItem - Individual filter option with checkbox
  • FilterIndicator - Visual checkbox indicator
  • FilterEmpty - Empty state when no options match
  • FilterSeparator - Visual separator between groups
  • FilterTrigger - Collapsible trigger for accordion-style filters
  • FilterReset - Reset button that automatically clears selections

Features

  • Multi-select - Support for selecting multiple filter options
  • Search - Built-in search input to filter options
  • Grouping - Organize filters into logical groups
  • Reset - One-click reset to clear all selections
  • Keyboard navigation - Full keyboard support via reka-ui Combobox
  • Animations - Smooth transitions for content visibility
  • Accessibility - ARIA-compliant with proper focus management

Examples

Basic Filter

A simple filter without groups.

<script setup lang="ts">
import { ref } from 'vue'
import {
  Filter,
  FilterContent,
  FilterIndicator,
  FilterInput,
  FilterItem,
  FilterList,
} from '@/components/ui/filter'

const selected = ref<string[]>([])

const options = [
  { option: 'Red', count: 24 },
  { option: 'Blue', count: 18 },
  { option: 'Green', count: 12 },
]
</script>

<template>
  <Filter v-model="selected" multiple>
    <FilterInput placeholder="Search colors..." />
    <FilterContent>
      <FilterList>
        <FilterItem
          v-for="opt in options"
          :key="opt.option"
          :value="opt.option"
          :option="opt"
        >
          <FilterIndicator />
        </FilterItem>
      </FilterList>
    </FilterContent>
  </Filter>
</template>

With Trigger

Use FilterTrigger for accordion-style collapsible filters.

<script setup lang="ts">
import { ref } from 'vue'
import {
  Filter,
  FilterContent,
  FilterIndicator,
  FilterItem,
  FilterList,
  FilterTrigger,
} from '@/components/ui/filter'

const selected = ref<string[]>([])
</script>

<template>
  <Filter v-model="selected" multiple>
    <FilterTrigger>Colors</FilterTrigger>
    <FilterContent>
      <FilterList>
        <FilterItem value="red" :option="{ option: 'Red', count: 24 }">
          <FilterIndicator />
        </FilterItem>
      </FilterList>
    </FilterContent>
  </Filter>
</template>