CommerceCategoryFilters

Filter sidebar for a category page: a stack of collapsible filter groups (price, color, size, brand). Uses native <details> so no JS is needed for collapse — Server Component friendly. Each group's controls are caller-supplied; state and submission live with the consumer.

Installation

pnpm
pnpm dlx @hex-core/cli add commerce-category-filters

Usage

tsx
import { CommerceCategoryFilters } from "@/components/ui/commerce-category-filters"

API Reference

PropTypeDefaultDescription
groupsrequired
objectReadonlyArray<{ title; content: ReactNode; defaultOpen? }>. Filter groups. Each content is a caller-supplied stack of controls (Checkbox / RadioGroup / Slider / range Input).
title
ReactNodeOptional sidebar title (e.g. 'Filters').
actions
ReactNodeOptional header actions (e.g. a 'Clear all' link).
className
stringAdditional classes applied to the root <aside>.

AI Guidance

When to use

Use on a category / search results page beside the product grid. The block is layout-only — pass real controls (Checkbox, RadioGroup, Slider, range Input) in each group's content. Wire selection state and result filtering in the parent.

When not to use

Don't use for storefront top nav (use commerce-store-nav). Don't use for in-product settings (use app-settings). Don't put the entire facet tree here — group by ~3–6 most-useful facets.

Common mistakes

  • Putting form submission inside the block — the block doesn't render a form; wrap your controls in a parent <form> if you want classic submit, or wire onChange handlers per control.
  • Putting more than ~6 groups — long sidebars get ignored; lift secondary facets into a modal or 'More filters' affordance.
  • Forgetting `<Label htmlFor>` on inputs — accessible names are the consumer's job.

Accessibility

Root is an <aside> labelled 'Filters'. Each group uses native <details>/<summary> — keyboard-toggleable (Enter/Space) with built-in aria-expanded. The chevron rotates via CSS on [open]; it's aria-hidden so it doesn't pollute the summary's accessible name.

Token budget: 982