Une barre de puces de filtre qui défile, en React
La rangée de puces sous chaque barre de recherche — sujets YouTube, filtres de boutique, sélecteurs de tags — est un conteneur de défilement sur une seule ligne rempli de boutons à bascule. Les 10 % difficiles concernent ce qui se passe aux bords : de nouvelles puces apparaissant hors écran, des glissers qui ne doivent rien basculer, et des flèches qui savent quand elles sont inutiles.
Ajoutez un filtre — la rangée fait défiler la nouvelle puce jusqu'à la vue toute seule.
Modifier cet exemple en direct dans Storybook
Les cas limites sont la fonctionnalité
Toute rangée flex avec overflow-x: auto défile. Une barre de puces se distingue sur les détails :
- Une puce ajoutée hors écran doit se signaler. La démo défile jusqu'à chaque nouvelle puce avec
apiRef.current.scrollToItem(el, 'smooth', 'end')après le rendu — l'exemple d'ajout d'élément et de défilement vers celui-ci est exactement ce câblage. - Glisser pour défiler, cliquer pour basculer — jamais les deux. Les utilisateurs de bureau font glisser la rangée comme une surface tactile ; relâcher au-dessus d'une puce ne doit pas la faire basculer. La recette de glisser suit le geste et supprime exactement ce clic.
- Des flèches seulement quand elles sont utiles.
useLeftArrowVisible/useRightArrowVisiblesont câblées au même IntersectionObserver que tout le reste, donc les flèches se désactivent aux véritables bords — y compris après l'ajout ou la suppression de puces.
L'état reste entre vos mains
La bibliothèque défile ; elle ne possède pas la sélection. Les puces sont vos boutons — aria-pressed pour les bascules multi-sélection, un état ordinaire pour la sélection unique — et le menu a seulement besoin que chacune porte un itemId. Cela signifie que l'état des puces se compose avec ce que vous avez déjà : paramètres d'URL, une bibliothèque de formulaires, un modèle de filtre piloté par serveur. Supprimer une puce, c'est retirer un élément ; l'animer en sortie est l'exemple d'animation d'éléments.
Mobile : un avertissement sur le défilement du corps de page
Sur les écrans tactiles, un balayage horizontal à l'intérieur de la barre peut entraîner la page de côté avec lui sur certains navigateurs. Si vous constatez cela, l'exemple d'empêcher le défilement du corps montre le touch-action et le confinement de surdéfilement pour le verrouiller — CSS uniquement, aucune bibliothèque de gestes.
Le motif, minimal
Les puces sont des boutons à bascule avec un itemId ; une ref vers l'API du menu fait défiler une puce nouvellement ajoutée jusqu'à la vue.
function ChipBar({ options }: { options: string[] }) {
const apiRef = React.useRef<publicApiType>(null);
const [selected, setSelected] = React.useState<string[]>([]);
const toggle = (id: string) =>
setSelected((cur) =>
cur.includes(id) ? cur.filter((c) => c !== id) : [...cur, id],
);
// A chip appended off-screen scrolls itself into view.
const addChip = (id: string) => {
toggle(id);
requestAnimationFrame(() => {
const el = apiRef.current?.getItemElementById(id);
if (el) apiRef.current?.scrollToItem(el, 'smooth', 'end');
});
};
return (
<ScrollMenu apiRef={apiRef}>
{options.map((id) => (
<Chip itemId={id} key={id} pressed={selected.includes(id)}
onToggle={() => toggle(id)} />
))}
</ScrollMenu>
);
}Ou installez-le comme composant shadcn
L'élément de registre chip-bar fournit ceci comme composant contrôlé — options, selected, onSelectedChange — stylé avec Tailwind dans votre components/ui/ :
npx shadcn@latest add https://react-horizontal-scrolling-menu.dev/r/chip-bar.json