Skip to content

Filter

A filter chip component for selecting/deselecting options. Unlike Radio, clicking an active chip deselects it (toggles off). In single-select mode, unselected items collapse when a selection is made, with a × reset button to clear. Use multiple for multi-select behavior.

NameCategoryDescriptionTypeDefault
type? StylePreset theme color for all filter items'primary' | 'success' | 'warning' | 'danger' | 'info'
size? SizeSize for all filter items'large' | 'small'
color? ColorCustom hex color for all filter itemsstring
disabled? StateWhether to disable all filter itemsbooleanfalse
disabled? StateWhether disabledbooleanfalse
multiple? BehaviorWhether to enable multi-select mode, allowing multiple items to be active simultaneouslybooleanfalse
name? BehaviorNative name attributestring
model-value / v-model? ContentBinding value. Single mode: clicking active item resets to undefined. Multiple mode: array of valuesstring | number | (string | number)[]
options? ContentArray of filter items, each with value, label, disabledFilterOptionProps[]
value? ContentIdentifier value of the filter itemstring | number
label? ContentLabel textstring
change? EventTriggered when selected value changes. Value is undefined when deselected(value: FilterValueType | FilterValueType[] | undefined) => void
default? SlotCustom filter item content (use PxFilterItem)
default? SlotCustom label content

Basic Usage

Bind v-model and provide options. Click a chip to select it; click again to deselect.

<template>
  <div class="demo-filter">
    <px-filter v-model="selected" :options="options" />
    <p class="demo-filter__result">Selected: {{ selected ?? 'none' }}</p>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const selected = ref<string | number | undefined>('vue');
const options = [
  { value: 'vue', label: 'Vue' },
  { value: 'react', label: 'React' },
  { value: 'angular', label: 'Angular' },
  { value: 'svelte', label: 'Svelte' },
];
</script>

<style scoped>
.demo-filter {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.demo-filter__result {
  font-family: var(--px-font-family);
  font-size: 14px;
  color: var(--px-text-color-secondary);
}
</style>

Disabled State

Use disabled on the group to disable all items, or on individual options.

<template>
  <div class="demo-filter">
    <p class="demo-filter__label">Group disabled:</p>
    <px-filter :options="options" disabled />
    <p class="demo-filter__label">Individual disabled:</p>
    <px-filter v-model="selected" :options="mixedOptions" />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const selected = ref<string | number | undefined>('a');
const options = [
  { value: 'a', label: 'Alpha' },
  { value: 'b', label: 'Beta' },
  { value: 'c', label: 'Gamma' },
];
const mixedOptions = [
  { value: 'a', label: 'Enabled' },
  { value: 'b', label: 'Disabled', disabled: true },
  { value: 'c', label: 'Enabled' },
];
</script>

<style scoped>
.demo-filter {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.demo-filter__label {
  font-family: var(--px-font-family);
  font-size: 14px;
  color: var(--px-text-color-secondary);
  margin: 0;
}
</style>

Type

Use type property to apply preset theme colors.

<template>
  <div class="demo-filter">
    <px-filter v-model="v1" :options="options" type="primary" />
    <px-filter v-model="v2" :options="options" type="success" />
    <px-filter v-model="v3" :options="options" type="warning" />
    <px-filter v-model="v4" :options="options" type="danger" />
    <px-filter v-model="v5" :options="options" type="info" />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const options = [
  { value: 'a', label: 'Alpha' },
  { value: 'b', label: 'Beta' },
  { value: 'c', label: 'Gamma' },
];

const v1 = ref<string | number | undefined>('a');
const v2 = ref<string | number | undefined>('a');
const v3 = ref<string | number | undefined>('a');
const v4 = ref<string | number | undefined>('a');
const v5 = ref<string | number | undefined>('a');
</script>

<style scoped>
.demo-filter {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
</style>

Custom Color

Use color property to set a custom hex color for the active state.

<template>
  <div class="demo-filter">
    <px-filter v-model="v1" :options="options" color="#ff6b6b" />
    <px-filter v-model="v2" :options="options" color="#20c997" />
    <px-filter v-model="v3" :options="options" color="#845ef7" />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const options = [
  { value: 'a', label: 'Alpha' },
  { value: 'b', label: 'Beta' },
  { value: 'c', label: 'Gamma' },
];

const v1 = ref<string | number | undefined>('a');
const v2 = ref<string | number | undefined>('a');
const v3 = ref<string | number | undefined>('a');
</script>

<style scoped>
.demo-filter {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
</style>

Different Sizes

Use size property to set the filter chip size.

<template>
  <div class="demo-filter">
    <px-filter v-model="v1" :options="options" size="small" />
    <px-filter v-model="v2" :options="options" />
    <px-filter v-model="v3" :options="options" size="large" />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const options = [
  { value: 'a', label: 'Small' },
  { value: 'b', label: 'Default' },
  { value: 'c', label: 'Large' },
];

const v1 = ref<string | number | undefined>('a');
const v2 = ref<string | number | undefined>('b');
const v3 = ref<string | number | undefined>('c');
</script>

<style scoped>
.demo-filter {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
}
</style>

Multiple Selection

Use multiple prop to enable multi-select mode. Multiple items can be active simultaneously, and clicking the × button clears all selections.

<template>
  <div class="demo-filter">
    <px-filter v-model="selected" :options="options" multiple />
    <p class="demo-filter__result">Selected: {{ selected.length ? selected.join(', ') : 'none' }}</p>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const selected = ref<(string | number)[]>(['vue']);
const options = [
  { value: 'vue', label: 'Vue' },
  { value: 'react', label: 'React' },
  { value: 'angular', label: 'Angular' },
  { value: 'svelte', label: 'Svelte' },
];
</script>

<style scoped>
.demo-filter {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.demo-filter__result {
  font-family: var(--px-font-family);
  font-size: 14px;
  color: var(--px-text-color-secondary);
}
</style>

Slot Children

Use PxFilterItem as slot children for more control over individual items.

<template>
  <div class="demo-filter">
    <px-filter v-model="selected" type="primary">
      <px-filter-item value="all" label="All" />
      <px-filter-item value="photos" label="Photos" />
      <px-filter-item value="videos" label="Videos" />
      <px-filter-item value="documents" label="Documents" />
    </px-filter>
    <p class="demo-filter__result">Selected: {{ selected ?? 'none' }}</p>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const selected = ref<string | number | undefined>('all');
</script>

<style scoped>
.demo-filter {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.demo-filter__result {
  font-family: var(--px-font-family);
  font-size: 14px;
  color: var(--px-text-color-secondary);
}
</style>