Filter

A single-select row of chips with a reset, for faceted product/category filtering. Radio semantics: one chip at a time; the reset clears the choice. Pair with FilterItems.

Colors

Real use · category filter

Showing: All

Using Filter

Silica ships one design system through three paths. They share a class vocabulary but are not interchangeable — pick the one that matches what you are building.

Plain HTML — CSS classes

The Tailwind v4 plugin. Works in any framework or none — Rails, Django, PHP, Go, a static file. This path ships no JavaScript, so Filter is styled but inert: its behavior comes from toggle-group. For that behavior with no framework, use the node-tree path below.

/* in your CSS */
@import "tailwindcss";
@plugin "@wizeworks/silicaui";

Root class filter, with 10 modifiers:

  • .filter
  • .filter-accent
  • .filter-error
  • .filter-info
  • .filter-item
  • .filter-neutral
  • .filter-primary
  • .filter-reset
  • .filter-secondary
  • .filter-success
  • .filter-warning

React

Typed components over those same classes, with behavior and accessibility from Base UI.

npm i @wizeworks/silicaui-react
import { Filter } from "@wizeworks/silicaui-react";

Props

FilterProps
PropTypeRequiredDescription
valuestringnoControlled selected value (undefined = nothing selected).
defaultValuestringnoUncontrolled initial value.
onValueChange(value: string | undefined) => voidnoFires with the new value, or undefined when reset.
colorSilicaColornoAccent for the selected chip.
disabledbooleannoDisable every chip + the reset.
showResetbooleannoRender the reset (×) once something is selected (default true).
resetLabelstringnoAccessible label for the reset control.
FilterItemProps
PropTypeRequiredDescription
valuestringyesThis chip's value.

Source of the demo above

The exact file that renders the examples above, so it can never drift from them. It imports a few of this site’s own layout helpers (../lib/…), so read it for the component calls rather than copying it whole.

Show source
import { useState } from "react";
import { Filter, FilterItem } from "@wizeworks/silicaui-react";
import { Section } from "../lib/Section";
import { COLORS } from "../lib/data";

const CATEGORIES = ["All", "Apparel", "Footwear", "Accessories", "Sale"];

export function FilterDemo() {
    const [category, setCategory] = useState<string | undefined>("All");

    return (
        <>
            <Section title="Colors">
                <div className="flex flex-col gap-3">
                    {COLORS.slice(0, 6).map((color) => (
                        <Filter key={color} color={color} defaultValue="all">
                            <FilterItem value="all">All</FilterItem>
                            <FilterItem value="new">New</FilterItem>
                            <FilterItem value="sale">Sale</FilterItem>
                        </Filter>
                    ))}
                </div>
            </Section>

            <Section title="Real use · category filter">
                <div className="flex flex-col gap-2">
                    <Filter color="primary" value={category} onValueChange={setCategory}>
                        {CATEGORIES.map((c) => (
                            <FilterItem key={c} value={c}>
                                {c}
                            </FilterItem>
                        ))}
                    </Filter>
                    <p className="text-sm opacity-60">
                        Showing: {category ?? "nothing selected"}
                    </p>
                </div>
            </Section>
        </>
    );
}

Vanilla — node tree to HTML

Filter — a single-select chip row with a reset. This is the EXISTING toggle-group behavior, not a new one: same single-select press semantics, same roving focus, same aria-pressed buttons. Build a node tree, project it with toHtml(), and let the zero-dependency runtime hydrate it. This is the path for generated or user-authored documents — a site builder, CMS output, a static export.

npm i @wizeworks/silicaui-html @wizeworks/silicaui-behaviors
import { atom, toHtml } from "@wizeworks/silicaui-html";

const node = atom("Filter", "filter", { /* props */ }, [/* children */]);
const markup = toHtml(node);

Styling on this path is the class string in the second argument — the same classes as the Plain HTML section above. There is no color prop here; write "filter filter-primary" rather than passing a colour as a prop.

Takes children
yes
Hydrated by
toggle-group

Load @wizeworks/silicaui-behaviors on the page or this markup renders correctly and does nothing.

The full API for Filter, on every path, is available through the Silica MCP server.