React + MotionFiltres

Contrôle segmenté

Une rangée d’options où une pastille colorée glisse jusqu’à celle que vous choisissez.

Réglages

3

Code

import { useId, useState } from "react";
import { motion } from "framer-motion";

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 SegmentedControlProps {
  accent?: string;
  size?: keyof typeof sizeMap;
  options?: string[];
  value?: string;
  onChange?: (value: string) => void;
}

export default function SegmentedControl({
  accent = "#0071e3",
  size = "md",
  options = ["Design", "Code", "Audio"],
  value,
  onChange,
}: SegmentedControlProps) {
  const [internal, setInternal] = useState(options[0] ?? "");
  const layoutId = useId();
  const active = value ?? internal;
  const current = options.includes(active) ? active : options[0];
  const s = sizeMap[size];

  const select = (o: string) => {
    if (value === undefined) setInternal(o);
    onChange?.(o);
  };

  return (
    <div className="flex rounded-full bg-black/5 p-1 dark:bg-white/10">
      {options.map((o) => (
        <button
          key={o}
          type="button"
          aria-pressed={current === o}
          onClick={() => select(o)}
          className={`relative rounded-full font-medium ${s.pad} ${s.text}`}
        >
          {current === o && (
            <motion.span
              layoutId={layoutId}
              className="absolute inset-0 rounded-full"
              style={{ backgroundColor: accent }}
              transition={{ type: "spring", stiffness: 380, damping: 30 }}
            />
          )}
          <span
            className="relative z-10"
            style={{ color: current === o ? "#ffffff" : undefined }}
          >
            {o}
          </span>
        </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

Un contrôle segmenté sert à changer de vue, pas à filtrer : « Mensuel / Annuel » sur une page de tarifs, « Liste / Carte » dans une recherche immobilière ou « Jour / Semaine / Mois » dans un agenda. Comme la pastille glisse au lieu de sauter, on voit ce qui a changé. Pensez à ce segmented control dès qu’il y a deux à quatre choix.

Au-delà de quatre options, l’espace manque, surtout sur mobile : raccourcissez la liste ou passez à des onglets. Choisissez une couleur d’accent assez contrastée, car le libellé sélectionné passe en blanc.