Rangée horizontale façon Netflix en React

La rangée d'affiches que vous parcourez sur chaque site de streaming n'est pas un carrousel — c'est un menu. Rien ne s'aligne, rien ne se lance automatiquement ; elle repose sur le défilement natif à inertie, avec des flèches superposées par-dessus. C'est exactement ce que fournit react-horizontal-scrolling-menu : vos cartes, le défilement natif, et une visibilité par élément pour que les flèches sachent quand se cacher.

Faites-la glisser, ou survolez la rangée — les flèches apparaissent en fondu sur les bords, et chacune disparaît quand son extrémité de la rangée est atteinte.

Pourquoi ce n'est pas un travail de carrousel

Une rangée Netflix n'affiche jamais une seule diapositive à la fois. Les éléments sont volontairement coupés en partie sur les bords — l'affiche tronquée est l'indice visuel qui dit « il y en a plus ». Les moteurs de carrousel luttent contre cela : ils s'approprient la couche de gestes avec des transformations JavaScript, s'alignent sur des limites de diapositives, et réimplémentent l'inertie que les navigateurs de vos utilisateurs possèdent déjà. Sur une rangée de cartes cliquables, tout cela est superflu.

Le défilement natif vous donne l'inertie, le tactile, le trackpad et la barre de défilement gratuitement. Les deux choses qu'il ne vous donne pas sont les flèches superposées et le fait de savoir quelles cartes sont à l'écran — et ce sont justement les deux choses qu'ajoute cette bibliothèque, via useIsVisible par élément et un état des flèches conscient des bords.

Les trois détails qui vendent l'effet

Faire monter en charge : rangées paresseuses et longs rails

Les interfaces de streaming empilent des dizaines de rangées avec des centaines de cartes. Comme les éléments sont du DOM ordinaire dans un conteneur de défilement natif, rien ne se re-rend au défilement — l'exemple de performance fait tourner 300 éléments sans virtualisation. La visibilité par élément offre aussi le chargement paresseux d'images gratuitement : affichez un espace réservé jusqu'à ce que useIsVisible signale que la carte est à l'écran.

Si votre rangée doit boucler à la fin, c'est le seul endroit où la sémantique des diapositives aide vraiment — voir la recette de boucle infinie pour la version côté application d'environ 60 lignes, avant de vous tourner vers un moteur de carrousel.

Le motif, minimal

Superposez des flèches sur une rangée à défilement natif — la démo ci-dessus, c'est cette structure plus le style. Le code source complet, prêt à l'emploi, avec glisser et fondu des bords, est fourni ci-dessous comme composant shadcn.

MediaRow.tsx
function MediaRow({ children }: { children: React.ReactNode }) {
  return (
    <div className="group relative">
      <ScrollMenu Header={<OverlayArrows />} wrapperClassName="edge-fade">
        {children}
      </ScrollMenu>
    </div>
  );
}

// Rendered as Header, so it lives inside the menu's VisibilityContext
// and can sit absolutely positioned over the row ends.
function OverlayArrows() {
  const api = React.useContext<publicApiType>(VisibilityContext);
  const atStart = api.useLeftArrowVisible();
  const atEnd = api.useRightArrowVisible();
  return (
    <>
      <button
        className="overlay-arrow left-0"
        hidden={atStart}
        onClick={() => api.scrollPrev()}
      >

      </button>
      <button
        className="overlay-arrow right-0"
        hidden={atEnd}
        onClick={() => api.scrollNext()}
      >

      </button>
    </>
  );
}

/* .edge-fade — the Netflix edge, one CSS line:
   mask-image: linear-gradient(to right,
     transparent, black 40px, black calc(100% - 40px), transparent); */

Ou installez-le comme composant shadcn

L'élément de registre media-row est exactement ce motif — flèches au survol, fondu des bords en dégradé, glisser pour défiler — sous forme de composant stylé avec Tailwind dans votre components/ui/, à vous de l'éditer :

shadcn
npx shadcn@latest add https://react-horizontal-scrolling-menu.dev/r/media-row.json

Exemples associés

Tous les exemples (21)