Filter control with selectable options in a popover.
v-model expects an array of { name, active? } objects. The pill is "active" when any item has active: true.default scoped slot overrides the pill label and receives: { label, filters, activeFilters, activeFilterList, activeFilterOverflow }.content slot overrides the popover body, replacing the default checkbox list with custom content (e.g., radio groups).modelValue array at mount. To keep active state in sync, mutate objects with forEach rather than replacing the array with map.use-dropdown for single-select filters where only one option applies at a time (e.g., conversation type).end-tooltip-text on the clear button so it has an accessible name for screen readers.label and the default slot — the pill must always have visible text identifying the filter category.map when toggling active state — mutate objects in-place with forEach to keep the pill's internal copy in sync.<dt-filter-pill :model-value="[{name: 'Email'}, {name: 'Phone'}, {name: 'Chat'}, {name: 'Social'}, {name: 'SMS'}]" label="Channel" > </dt-filter-pill>
The pill becomes active when any filter item has active: true.
<dt-filter-pill :model-value="[{name: 'Headquarters', active: true}, {name: 'Westside'}, {name: 'Downtown'}]" label="Contact centers" > </dt-filter-pill>
<dt-filter-pill label="Conversation type" disabled></dt-filter-pill>
Its value is reflected in the filter set but cannot be opened, cleared, or modified. Functionally and visually distinct from disabled.
<dt-filter-pill :model-value="[{name: 'Headquarters', active: true}, {name: 'Westside', active: true}, {name: 'Downtown'}]" label="Contact centers" read-only ></dt-filter-pill>
200 (small) is the default.
<dt-filter-pill label="{size}" size="{size}" />A clear button appears when any filter is active. It emits the reset event when clicked.
<dt-filter-pill label="Channel" :model-value="[{ name: 'Option 1' }, { name: 'Option 2', active: true }, { name: 'Option 3' }]" end-tooltip-text="Remove" > </dt-filter-pill>
Setting the :show-clear="false" prop hides the reset/clear button.
<dt-filter-pill :model-value="[{name: '0–5 min', active: true}, {name: '5–15 min'}, {name: '15–30 min'}, {name: '30+ min'}]" label="Duration" :show-clear="false" > </dt-filter-pill>
Setting defer-selection holds checkbox changes in a pending state until Apply is clicked.
Cancel, Escape, or clicking outside discards pending changes.
<dt-filter-pill :model-value="[{name: 'Email'}, {name: 'Phone', active: true}, {name: 'Chat'}, {name: 'Social'}, {name: 'SMS'}]" label="Channel" end-tooltip-text="Remove" defer-selection popover-footer-class="d-pie-200 d-py-150" > </dt-filter-pill>
Setting use-dropdown switches the overlay from a popover to a dropdown with keyboard-navigable
list items. This provides arrow key navigation, highlight management, and Enter/Space selection
out of the box — ideal for single-select filter patterns.
<dt-filter-pill :model-value="[{name: 'All Conversations'}, {name: 'Only Calls'}, {name: 'Only Meetings'}, {name: 'Only Digital'}]" :start-tooltip-text="selectedType !== 'All Conversations' ? 'Conversation type' : ''" end-tooltip-text="Remove" use-dropdown @clear="resetType" > <template #default> {{ selectedType === 'All Conversations' ? 'Conversation type' : selectedType }} </template> <template #content="{ close }"> <dt-list-item v-for="filter in conversationTypes" :key="filter.name" role="menuitem" navigation-type="arrow-keys" :selected="filter.name === selectedType" @click="selectType(filter.name, close)" > {{ filter.name }} </dt-list-item> </template> </dt-filter-pill>
Using the default slot, you can override the label prop.
Using the default scoped slot, you can display a count of active filters alongside the label.
<dt-filter-pill :model-value="[{name: 'Address', active: true}, {name: 'Call Purpose', active: true}, {name: 'Action Item'}, {name: 'Negative Sentiment'}, {name: 'Warranty Inquiry', active: true}]" label="Contact centers" end-tooltip-text="Remove" > <template #default="{ label, filters, activeFilters }"> {{ label }}<template v-if="activeFilters.length">: <strong> {{ activeFilters.length === filters.length ? 'All' : activeFilters.length }} </strong></template> </template> </dt-filter-pill>
Shows the first active filter name using activeFilterList, with overflow count for remaining selections (e.g., "Email +2").
<dt-filter-pill :model-value="[{name: 'Email', active: true}, {name: 'Phone', active: true}, {name: 'Chat', active: true}, {name: 'Social'}, {name: 'SMS'}]" label="Channel" end-tooltip-text="Remove" > <template #default="{ label, filters, activeFilters, activeFilterList, activeFilterOverflow }"> {{ label }}<template v-if="activeFilters.length">: <strong> {{ activeFilters.length === filters.length ? 'All' : activeFilterList }} </strong> <template v-if="activeFilterOverflow"> {{ activeFilterOverflow }}</template></template> </template> </dt-filter-pill>
Combining the default and content slots with a radio group creates a single-select filter.
The label updates to show the selected option, and a clear button resets to the default.
<dt-filter-pill :model-value="[{name: 'All Conversations'}, {name: 'Only Calls'}, {name: 'Only Meetings'}, {name: 'Only Digital'}]" :start-tooltip-text="selectedConversationType !== 'All Conversations' ? 'Conversation type' : ''" end-tooltip-text="Remove" @clear="selectedConversationType = 'All Conversations'" > <template #default> {{ selectedConversationType === 'All Conversations' ? 'Conversation type' : selectedConversationType }} </template> <template #content> <dt-radio-group v-model="selectedConversationType" name="conversation-type-doc-filter" > <dt-radio v-for="filter in conversationTypes" :key="filter.name" :label="filter.name" :value="filter.name" @update:model-value="$event => selectedConversationType = $event" /> </dt-radio-group> </template> </dt-filter-pill>
Using the content slot, you can override the popover content with custom markup.
<dt-filter-pill :model-value="[{name: 'Contains'}, {name: 'Starts with'}]" label="Keyword" > <template #content> Enter a keyword to filter results </template> </dt-filter-pill>
Filter Pill popover content renders outside the DOM tree. Use the contentMode prop to apply color mode (invert, light, dark) to the positioned content. See Positioned Components for details.
<dt-filter-pill content-mode="invert">...</dt-filter-pill> <dt-filter-pill content-mode="dark">...</dt-filter-pill> <dt-filter-pill content-mode="light">...</dt-filter-pill>
The filter pill is built on DtButton and DtPopover/DtDropdown, inheriting their keyboard and screen reader support.
| Key | Action |
|---|---|
| Enter / Space | Opens the popover or dropdown; toggles checkboxes inside |
| Arrow Up / Arrow Down | Opens the popover; navigates list items in dropdown mode |
| Escape | Closes the popover or dropdown, discarding pending changes in deferred mode |
| Tab | Moves focus between the primary button, checkboxes, footer actions, and the clear button |
aria-disabled="true" in read-only mode instead of disabled, preserving focusability while indicating the control is not interactive.aria-label set to the pill's label prop, giving screen readers context for the list of options.aria-label set to endTooltipText (or a localized default), ensuring the icon-only button has an accessible name.label prop or populate the default slot so the pill has visible text.start-tooltip-text to the original label so the full context remains available on hover and to assistive technology.end-tooltip-text for the clear button to give it a meaningful accessible name (e.g., "Remove filter").import { DtFilterPill } from '@dialpad/dialtone-vue';
Name
|
Type
|
|---|---|
content | Allows you to override the popover content, only use this if you need custom behavior |
default | Allows you to customize the label slot |
footerContent | Allows you to customize the popover footer. Receives { close, apply, cancel } bindings. |
headerContent | Allows you to customize the popover header |
startIcon | Icon displayed before the label |
Name
|
Default
|
Type
|
|---|---|---|
contentMode |
"light"
|
"dark"
|
"invert"
Applies a color mode to the positioned content element. | |
deferSelection | false | boolean When true, checkbox changes are held in a pending state until the user
clicks Apply. Cancel or closing the popover discards pending changes.
Only applies to popover mode (not useDropdown). |
disabled | false | boolean HTML disabled attribute |
dropdownListClass | '' | string|array|object Additional CSS class(es) applied to the dropdown list wrapper.
Only applies when useDropdown is true. |
endTooltipText | '' | string Text shown in tooltip when you hover the end button,
required as it is an icon only button |
label | string Label of the button | |
labelClass | '' | string|array|object Additional CSS class(es) applied to the label wrapper element. |
modelValue | [] | array Array of filters to display in the popover,
should be an array of objects with |
popoverAppendTo | 'body' |
"body"
|
"parent"
|
"root"
|
"HTMLElement"
Sets the element to which the
popover component
is going to append to |
popoverContentClass | '' | string|array|object Additional CSS class(es) applied to the popover content area.
Only applies when useDropdown is false. |
popoverDialogClass | '' | string|array|object Additional CSS class(es) applied to the popover dialog element.
Only applies when useDropdown is false. |
popoverFallbackPlacements | ['auto'] |
"top"
|
"top-start"
|
"top-end"
|
"right"
|
"right-start"
|
"right-end"
|
"left"
|
"left-start"
|
"left-end"
|
"bottom"
|
"bottom-start"
|
"bottom-end"
|
"auto"
|
"auto-start"
|
"auto-end"
If the dropdown does not fit in the direction described by "popoverPlacement",
it will attempt to change it's direction to the "popoverFallbackPlacements". |
popoverFooterClass | '' | string|array|object Additional CSS class(es) applied to the outer popover footer element ( |
popoverHeaderClass | '' | string|array|object Additional CSS class(es) applied to the outer popover header element ( |
popoverMaxHeight | '' | string Determines maximum height for the popover before overflow.
Possible units rem|px|em |
popoverMaxWidth | '' | string Determines maximum width for the popover before overflow.
Possible units rem|px|%|em |
popoverPadding | 'large' |
"none"
|
"small"
|
"medium"
|
"large"
Padding size class for the popover content. |
popoverPlacement | 'bottom-start' |
"top"
|
"top-start"
|
"top-end"
|
"right"
|
"right-start"
|
"right-end"
|
"left"
|
"left-start"
|
"left-end"
|
"bottom"
|
"bottom-start"
|
"bottom-end"
|
"auto"
|
"auto-start"
|
"auto-end"
The direction the popover displays relative to the anchor.
Tippy.js docs |
readOnly | false | boolean When true, the pill cannot be interacted with but does not
receive disabled visual styling. Adds |
showClear | true |
"true"
|
"false"
Shows the clear button when a filter is active |
size | 200 |
"100"
|
"200"
|
"300"
|
"400"
|
"500"
The size of the button. |
startTooltipText | '' | string Text shown in tooltip when you hover the start button,
required if no content is passed to default slot |
useDropdown | false | boolean When true, uses DtDropdown instead of DtPopover as the overlay.
Provides keyboard navigation (arrow keys) for list items.
Default content renders DtListItem elements (single-select)
instead of checkboxes (multi-select). |
Name
|
Type
|
|---|---|
apply | Emitted when deferred selection is applied |
clear | Boolean | Array Emitted when clicking the clear button |
open | Boolean | Array Emitted when popover is shown or hidden |
update:modelValue | Array Emitted when the active filters change |
Class
|
Applies to
|
Description
|
|---|
Filter Pill documentation last updated Friday, September 4, 2026
fix/popover-modal-zindex-scope