Filter Chip
Shows one applied filter, its field and value, with an optional button to remove it.
@zenoxai/ui/components/filter-chip Markdownfunction FilterChipDemo() {
return <FilterChip label="Severity" value="Critical" onRemove={() => {}} />
}Usage
import { FilterChip } from "@zenoxai/ui/components/filter-chip"
export function SeverityFilter({ onRemove }: { onRemove: () => void }) {
return <FilterChip label="Severity" value="Critical" onRemove={onRemove} />
}
Use filter chips above a table or list to show which filters are applied, one chip per field.
label is the field and renders in secondary text followed by a colon; value renders in
medium weight. Pass onRemove and the chip gets a remove button that calls it.
The chip is a <span> and is not clickable itself. To pick filters, use a
Select, a Dropdown Menu or a
Combobox; to switch a quick filter on and off, use a
Toggle. For a status or a category that is not a filter, use a
Badge.
When a field has several values, join them in one chip (“Critical, High”) rather than rendering a chip per value.
Examples
Variants
<>
<FilterChip label="Status" value="Open" />
<FilterChip variant="active" label="Severity" value="High" />
<FilterChip variant="ghost" label="Tenant" value="Acme Corp" />
</>| Variant | Use for |
|---|---|
default |
Applied filters in a filter bar. |
active |
A filter that differs from the view’s default, to draw attention to it. |
ghost |
Filters inherited from context, such as the current tenant. |
Sizes
sm (20px) fits inside table cells and card headers, default (24px) is for filter bars, and
lg (28px) sits next to 28px buttons. default and lg use the 12.5px body text, sm the
10px caption size; the remove icon is 12px at sm and 14px otherwise.
<>
<FilterChip
size="sm"
label="Source"
value="CT logs"
onRemove={() => {}}
/>
<FilterChip label="Source" value="CT logs" onRemove={() => {}} />
<FilterChip
size="lg"
label="Source"
value="CT logs"
onRemove={() => {}}
/>
</>Filter bar
The applied filters of a list, each removable, with a link to clear them all. Keep the chips in the same order as the filter controls.
function FilterChipFilterBar() {
const [filters, setFilters] = React.useState([
{ id: "severity", label: "Severity", value: "Critical, High" },
{ id: "status", label: "Status", value: "Open" },
{ id: "asset", label: "Asset type", value: "Domain" },
{ id: "age", label: "First seen", value: "Last 7 days" },
])
if (filters.length === 0) {
return (
<p className="text-sm text-text-muted">No filters. Showing all alerts.</p>
)
}
return (
<div className="flex w-full max-w-lg flex-wrap items-center gap-2">
{filters.map((filter) => (
<FilterChip
key={filter.id}
label={filter.label}
value={filter.value}
onRemove={() =>
setFilters((current) => current.filter((f) => f.id !== filter.id))
}
/>
))}
<Button variant="link" size="xs" onClick={() => setFilters([])}>
Clear all
</Button>
</div>
)
}Custom content
Children render after the value, before the remove button. Use them for an icon, a count of hidden values, or a chip with no field name. Size icons yourself; the chip does not.
<>
<FilterChip
variant="active"
onRemove={() => {}}
removeAriaLabel="Remove domain filter"
>
<GlobeIcon className="size-3" />
acme-corp.com
</FilterChip>
<FilterChip
label="Tags"
value="phishing"
removeAriaLabel="Remove tags filter"
onRemove={() => {}}
>
<span className="text-text-muted">+2</span>
</FilterChip>
</>Accessibility
- The remove button is labelled “Remove filter
label” whenlabelis a string, and “Remove filter” otherwise. SetremoveAriaLabelwheneverlabelis not a string, so every button on the page has a distinct name. - Removing a chip removes the focused button with it. Move focus somewhere predictable after
onRemove: the next chip’s button, or the filter control when none are left. - The remove button is 16px square, under the 24px target size of WCAG 2.2. It meets the
spacing exception only while no other control sits within 4px of it, so keep at least
gap-2between chips and the controls around them.
API reference
Generated from the TypeScript source. className, style and children are accepted everywhere and omitted below.
FilterChip
FilterChip shows one applied filter as "label: value", with an optional remove button, in the bar above a list or table. For a static tag or a count, use Badge.
| Prop | Type | Default |
|---|---|---|
label | ReactNodeField/dimension being filtered (e.g. "Severity"). Renders before the colon. | - |
onRemove | (() => void)When present, renders an inline X button that calls this on click. | - |
removeAriaLabel | stringAccessible name of the remove button. Defaults to the English "Remove filter <label>" when `label` is a string, else "Remove filter"; pass a translated one. | - |
size | "default" | "sm" | "lg" | nullHeight: `sm` 20px, `default` 24px, `lg` 28px. Text is the 12.5px body size, 10px at `sm`; the remove icon is 12px at `sm`, 14px otherwise. | - |
value | ReactNodeFilter value (e.g. "Critical"). Renders bold after the colon. | - |
variant | "default" | "ghost" | "active" | null`default` is outlined; `active` is tinted with the primary color, to mark the chip in focus; `ghost` has a muted fill and no border. | - |