Skip to content

FilterGroup

Organism

Filter Group lets users refine a list with multiple criteria. Options are grouped in segments; users can toggle individual filters or an optional “All” parent. Use it for compact multi-filter UIs (for example table headers), not as a general-purpose Multiselect form field.

Playground

TheAppWrapper is set to max-width: 380px

FilterGroup with numerical values

Selected values: []
Tooltip
Tooltip

FilterGroup with alphabetical values

Selected values: []
Tooltip
        
          
< FilterGroup
  segments = "[ { "title": "Segment 1", "hasAllOption": true, "allOptionLabel": "Check them all", "options": [ { "value": 1, "text": "Option 1 is a very long option, so we can check whether truncation works with it", "isDisabled": false, "isSelected": false }, { "value": 4, "text": "N/mm<sup>2</sup>", "isSelected": false }, { "value": 7, "text": "Option 7", "isSelected": false } ] }, { "title": "", "allOptionLabel": "All the single ladies", "hasAllOption": false, "options": [ { "value": 2, "text": "Option 2", "isSelected": false }, { "value": 5, "text": "Option 5", "isSelected": false }, { "value": 3, "text": "Option 3", "isSelected": false }, { "value": 6, "text": "Option 6", "isSelected": false } ] } ]"
  alignment = "right"
  tooltip = "Tooltip"
  tooltipPosition = "top-left"
/>

Properties

ts
export interface FilterGroupGenericProps<T extends string | number> extends TooltipProps {
  modelValue: T[];
  segments: FilterGroupOptionSegment<T>[];
  disabled?: boolean;
  alignment?: 'left' | 'right';
  sortOptions?: FilterGroupSortOptions;
  // searchOptions?: FilterGroupSearchOptions;
}

export interface FilterGroupSortOptions {
  order: 'asc' | 'ascending' | 'desc' | 'descending';
  target: 'text' | 'value';
  ignoreCase?: boolean;
}

export interface FilterGroupSearchOptions {
  enableSearch: boolean;
  caseSensitive?: boolean;
  placeholder?: string;
}
ts
export interface FilterGroupOptionSegment<T extends string | number> {
  title?: string;
  hasAllOption?: boolean;
  allOptionLabel?: string;
  options: FilterGroupOptionGeneric<T>[];
}

export interface FilterGroupOptionGeneric<T extends string | number> {
  text: string | number,
  value: T;
  isSelected: boolean;
  hasAction?: boolean;
  isDisabled?: boolean;
}

Anatomy

  1. Filter button - Nested Icon Button. Opens and closes the dropdown. Shows a filters-applied indicator when any option is selected.

  2. Dropdown container - Panel under the button listing filter segments and options.

  3. Filters applied indicator - Visual cue on the button that filters are active for the current view.

  4. Section label - Optional title per segment (e.g. category name). Omit when options are self-explanatory.

  5. Parent option (“All”) - Nested Checkbox. Checks or clears all non-disabled child options in the segment; supports indeterminate when partially selected.

  6. Child option - Nested Checkbox. Toggle a single filter; parent “All” stays in sync.

  7. Option without parent/child - Nested Checkbox when hasAllOption is off (short lists).

  8. Divider - Separates segments visually.

If option text overflows the container width, it truncates and the native title attribute shows the full label.




States
  • No filter applied.
  • Filters applied (indicator on the Filter button).
  • Dropdown expanded — Icon Button is :active.
  • Dropdown collapsed.
Variants
Sections
  • With sections and section labels.
  • With sections but no section labels.
  • Without sections.
All option
  • With parent–child “All” option controlling child options.
  • Without “All” options (typical for short lists of 1–4 items).
Dropdown alignment
  • Left-aligned relative to the Filter button.
  • Right-aligned relative to the Filter button.

Developer notes

  • Selections apply as the user toggles options; modelValue is the list of selected option values across segments.
  • Clicking outside the component closes the dropdown (click-outside on the root; no full-screen overlay).
  • Tab focuses the control; Enter when focused opens the dropdown; Arrow keys move through options; Enter toggles the highlighted option without closing the dropdown (unlike Select).
  • Tab again moves to the next control; Shift+Tab while browsing options returns focus to the filter control.
  • Use alignment (left | right) so the panel opens correctly in dense layouts (e.g. table headers).
  • Keep option isSelected in sync with modelValue when driving segments from outside.
vue
<script setup>
import { ref } from 'vue';
import { FilterGroup } from '@pohlcon/design-system';

const modelValue = ref([]);

const segments = [
  {
    title: 'Status',
    hasAllOption: true,
    allOptionLabel: 'All',
    options: [
      { value: 1, text: 'Open', isSelected: false },
      { value: 2, text: 'Closed', isSelected: false },
      { value: 3, text: 'Draft', isSelected: false },
    ],
  },
];
</script>

<template>
  <FilterGroup
    v-model="modelValue"
    :segments="segments"
    alignment="left"
  />
</template>