Skip to content

Filter Pill

Filter pills are used to filter content or selections.

The FilterGroup widget manages a set of filter options, supporting multi-selection and individual item colors.

By default, the FilterGroup uses the theme’s default colors.

class FilterGroupDefaultExample extends StatefulWidget {
@override
State<FilterGroupDefaultExample> createState() => _FilterGroupDefaultExampleState();
}
class _FilterGroupDefaultExampleState extends State<FilterGroupDefaultExample> {
Set<String> _selectedGroup = {'Red', 'Green'};
@override
Widget build(BuildContext context) {
return FilterGroup<String>(
items: [
FilterItem(value: 'Arm', label: const Text('Arm')),
FilterItem(value: 'Base', label: const Text('Base')),
FilterItem(value: 'Board', label: const Text('Board')),
FilterItem(value: 'Sensor', label: const Text('Sensor')),
const FilterItem(value: 'Servo', label: Text('Servo')),
],
selected: _selectedGroup,
onSelectionChanged: (newSelection) {
setState(() {
_selectedGroup = newSelection;
});
},
);
}
}

You can customize the color of each item by setting the activeColor property on the FilterItem.

class FilterGroupCustomExample extends StatefulWidget {
@override
State<FilterGroupCustomExample> createState() => _FilterGroupCustomExampleState();
}
class _FilterGroupCustomExampleState extends State<FilterGroupCustomExample> {
Set<String> _selectedGroup = {'Red', 'Green'};
@override
Widget build(BuildContext context) {
final theme = PrimeTheme.of(context);
return FilterGroup<String>(
items: [
FilterItem(value: 'Red', label: const Text('Red'), activeColor: theme.colorScheme.statusDangerDark),
FilterItem(value: 'Orange', label: const Text('Orange'), activeColor: theme.colorScheme.statusWarningDark),
FilterItem(value: 'Green', label: const Text('Green'), activeColor: theme.colorScheme.statusSuccessDark),
FilterItem(value: 'Blue', label: const Text('Blue'), activeColor: theme.colorScheme.statusInfoDark),
const FilterItem(value: 'Purple', label: Text('Purple'), activeColor: Color(0xFF9C27B0)),
],
selected: _selectedGroup,
onSelectionChanged: (newSelection) {
setState(() {
_selectedGroup = newSelection;
});
},
);
}
}

You can compose a FilterGroup with standalone FilterPill widgets to create complex toolbars. For example, you can add a search button next to the filters.

class FilterGroupCompositeExample extends StatefulWidget {
@override
State<FilterGroupCompositeExample> createState() => _FilterGroupCompositeExampleState();
}
class _FilterGroupCompositeExampleState extends State<FilterGroupCompositeExample> {
Set<String> _selectedSearch = {'Search'};
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
FilterPill(
label: const Icon(PrimeIcons.magnify),
isSelected: _selectedSearch.contains('Search'),
// give this pill custom funcitonality, such as search or making a bottom sheet appear.
onTap: () => setState(() => _selectedSearch.contains('Search') ? _selectedSearch.remove('Search') : _selectedSearch.add('Search')),
),
const SizedBox(width: 8),
FilterGroup<String>(
items: [
FilterItem(value: 'Arm', label: const Text('Arm')),
FilterItem(value: 'Base', label: const Text('Base')),
FilterItem(value: 'Board', label: const Text('Board')),
FilterItem(value: 'Sensor', label: const Text('Sensor')),
FilterItem(value: 'Servo', label: Text('Servo')),
],
selected: _selectedSearch,
onSelectionChanged: (newSelection) {
setState(() {
_selectedSearch = newSelection;
});
},
),
],
),
);
}
}

A basic filter pill. Tap to toggle selection state.

class BasicToggleExample extends StatefulWidget {
@override
State<BasicToggleExample> createState() => _BasicToggleExampleState();
}
class _BasicToggleExampleState extends State<BasicToggleExample> {
bool _isSelected = false;
@override
Widget build(BuildContext context) {
return FilterPill(
label: Text('Example'),
isSelected: _isSelected,
onTap: () => setState(() => _isSelected = !_isSelected),
);
}
}

Filter pills can include leading icons or be icon-only.

class IconToggleExample extends StatefulWidget {
@override
State<IconToggleExample> createState() => _IconToggleExampleState();
}
class _IconToggleExampleState extends State<IconToggleExample> {
bool _isSelected = false;
@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
spacing: 16,
children: [
FilterPill(
label: const Text('With Icon'),
leading: const Icon(PrimeIcons.viamFlutter, size: 16),
isSelected: _isSelected,
onTap: () => setState(() => _isSelected = !_isSelected),
),
FilterPill(
label: const Icon(PrimeIcons.magnify, size: 20),
isSelected: _isSelected,
onTap: () => setState(() => _isSelected = !_isSelected),
),
],
);
}
}