# V collapsible 12

> Sidebar filter panel with collapsible groups, checkboxes, and active count

A shadcn/ui block from the [@cnippet](https://ui.cnippet.dev/) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/cnippet/v-collapsible-12).

- Page, with a live preview: https://shadcn.exchange/r/cnippet/v-collapsible-12
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/cnippet/v-collapsible-12-light-62af1a02eb65d236.png
- Registry item: https://ui.cnippet.dev/r/v-collapsible-12.json
- Categories: collapsible
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://ui.cnippet.dev/r/v-collapsible-12.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `@cnippet/collapsible`

## Files

### `registry/default/variants/v-collapsible-12.tsx`

```tsx
//biome-ignore-all lint/style/noNonNullAssertion:<>
"use client";

import { ChevronDownIcon, FilterIcon, XIcon } from "lucide-react";
import { useState } from "react";
import { Badge } from "@/registry/default/ui/badge";
import { Button } from "@/registry/default/ui/button";
import { Checkbox } from "@/registry/default/ui/checkbox";
import {
  Collapsible,
  CollapsiblePanel,
  CollapsibleTrigger,
} from "@/registry/default/ui/collapsible";

const FILTERS = [
  {
    id: "category",
    label: "Category",
    options: ["Design", "Engineering", "Marketing", "Operations"],
  },
  {
    id: "status",
    label: "Status",
    options: ["Active", "Paused", "Archived"],
  },
  {
    id: "priority",
    label: "Priority",
    options: ["High", "Medium", "Low"],
  },
];

export function Pattern() {
  const [selected, setSelected] = useState<Record<string, Set<string>>>({});

  const toggle = (group: string, opt: string) =>
    setSelected((prev) => {
      const next = { ...prev, [group]: new Set(prev[group] ?? []) };
      next[group]!.has(opt) ? next[group]!.delete(opt) : next[group]!.add(opt);
      return next;
    });

  const totalActive = Object.values(selected).reduce(
    (sum, s) => sum + s.size,
    0,
  );

  return (
    <div className="w-full max-w-xs space-y-2">
      <div className="flex items-center justify-between">
        <div className="flex items-center gap-2">
          <FilterIcon className="size-4 text-muted-foreground" />
          <p className="font-semibold text-sm">Filters</p>
          {totalActive > 0 && <Badge size="sm">{totalActive}</Badge>}
        </div>
        {totalActive > 0 && (
          <button
            className="flex items-center gap-1 text-muted-foreground text-xs hover:text-foreground"
            onClick={() => setSelected({})}
            type="button"
          >
            <XIcon className="size-3" />
            Clear all
          </button>
        )}
      </div>
      {FILTERS.map((f) => (
        <Collapsible defaultOpen key={f.id}>
          <CollapsibleTrigger className="flex w-full items-center justify-between py-2 font-medium text-sm transition-colors hover:text-primary">
            <span className="flex items-center gap-2">
              {f.label}
              {(selected[f.id]?.size ?? 0) > 0 && (
                <Badge size="sm" variant="secondary">
                  {selected[f.id]?.size}
                </Badge>
              )}
            </span>
            <ChevronDownIcon className="size-3.5 in-data-panel-open:rotate-180 text-muted-foreground transition-transform duration-200" />
          </CollapsibleTrigger>
          <CollapsiblePanel>
            <div className="space-y-1.5 pb-3">
              {f.options.map((opt) => (
                <label
                  className="flex cursor-pointer items-center gap-2 text-muted-foreground text-sm hover:text-foreground"
                  key={opt}
                >
                  <Checkbox
                    checked={selected[f.id]?.has(opt) ?? false}
                    onCheckedChange={() => toggle(f.id, opt)}
                  />
                  {opt}
                </label>
              ))}
            </div>
          </CollapsiblePanel>
        </Collapsible>
      ))}
      <Button className="w-full" size="sm">
        Apply filters
      </Button>
    </div>
  );
}
```
