React + MotionFiltres

Chips de filtre

Des filtres en forme de pastille qu’on active et désactive, avec une petite coche qui apparaît à l’activation.

Réglages

5

Code

import { useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { Check } from "lucide-react";

const sizeMap = {
  sm: { pad: "px-3 py-1.5", text: "text-xs" },
  md: { pad: "px-4 py-2", text: "text-sm" },
  lg: { pad: "px-5 py-2.5", text: "text-base" },
} as const;

interface FilterChipsProps {
  accent?: string;
  size?: keyof typeof sizeMap;
  options?: string[];
  value?: string[];
  onChange?: (value: string[]) => void;
}

export default function FilterChips({
  accent = "#0071e3",
  size = "md",
  options = ["Design", "Code", "Audio", "Vidéo", "3D"],
  value,
  onChange,
}: FilterChipsProps) {
  const [internal, setInternal] = useState<string[]>(options.slice(0, 1));
  const active = value ?? internal;
  const s = sizeMap[size];

  const toggle = (o: string) => {
    const next = active.includes(o) ? active.filter((x) => x !== o) : [...active, o];
    if (value === undefined) setInternal(next);
    onChange?.(next);
  };

  return (
    <div className="flex w-full max-w-md flex-wrap justify-center gap-2">
      {options.map((o) => {
        const on = active.includes(o);
        return (
          <motion.button
            key={o}
            type="button"
            aria-pressed={on}
            whileTap={{ scale: 0.94 }}
            onClick={() => toggle(o)}
            className={`flex items-center gap-1.5 rounded-full border font-medium transition-colors ${s.pad} ${s.text}`}
            style={{
              borderColor: on ? accent : "oklch(1 0 0 / 14%)",
              backgroundColor: on ? `${accent}22` : "transparent",
              color: on ? accent : undefined,
            }}
          >
            <AnimatePresence initial={false}>
              {on && (
                <motion.span
                  initial={{ width: 0, opacity: 0 }}
                  animate={{ width: "auto", opacity: 1 }}
                  exit={{ width: 0, opacity: 0 }}
                  className="overflow-hidden"
                >
                  <Check className="h-3.5 w-3.5" />
                </motion.span>
              )}
            </AnimatePresence>
            {o}
          </motion.button>
        );
      })}
    </div>
  );
}

Prompt pour l’IA

Collez-le dans ChatGPT, Claude ou Cursor : le bloc sera adapté à votre projet avec ces réglages, même sans React.

Plus dans Filtres

Où l’utiliser

Les chips sont le moyen le plus rapide de filtrer une liste sans ouvrir de menu : types de cuisine sur un site de recettes, tailles dans une boutique de vêtements, thèmes d’un blog ou compétences sur un site d’emploi. Ces chips de filtre acceptent plusieurs choix à la fois, et la coche montre clairement ce qui est actif.

Elles fonctionnent mieux avec huit libellés courts au maximum, d’un ou deux mots. Avec des dizaines d’options, passez plutôt à une liste déroulante avec recherche. La petite taille convient dans les cartes, la grande sur mobile, où le doigt a besoin de place.