Des onglets défilants React qui défilent comme le navigateur
Une barre d'onglets cesse de tenir dès que votre produit dépasse six onglets. La solution n'est pas une police plus petite — c'est une barre qui défile : le débordement repose sur le navigateur, cliquer sur un onglet le centre, et les flèches n'apparaissent que s'il y a quelque part où aller.
Cliquez sur un onglet près du bord — il se centre lui-même par défilement.
Modifier cet exemple en direct dans Storybook
Le seul comportement qui compte : centrer à la sélection
Une barre d'onglets défilante ne tient que sur ce qui se passe quand vous cliquez sur un onglet au bord : il doit glisser vers le centre, révélant ses voisins des deux côtés. C'est un seul appel ici — scrollToItem(el, 'smooth', 'center') — câblé dans l'exemple de centrage au clic. Restaurer l'onglet actif au montage est le même appel avec 'auto', montré dans sauvegarder et restaurer la position.
Les flèches proviennent des mêmes données de visibilité : useLeftArrowVisible est faux uniquement tant que le premier onglet est hors écran, donc la flèche gauche s'affiche exactement quand elle est utile. Aucun code de mesure, aucun observateur de redimensionnement à écrire vous-même.
Si vous dépassez les onglets défilants de MUI
Les onglets variant="scrollable" de Material UI sont la bonne réponse à l'intérieur du système de design de Material — jusqu'à ce que vos « onglets » cessent d'être des onglets. MUI soude la barre à la sémantique de Tabs : une paire value/onChange, des panneaux d'onglets, et des boutons de défilement que MUI masque sur mobile par défaut. Dès que votre rangée contient des puces, des cartes, des avatars ou du contenu mixte, ou a besoin du glisser pour défiler, ou a besoin de savoir quels éléments sont visibles, vous luttez contre le composant plutôt que de l'utiliser.
Cette bibliothèque est la couche en dessous : une rangée défilante avec suivi de visibilité, sans aucun avis sur ce qu'est un « onglet ». Votre onglet est n'importe quel composant portant un itemId — stylez-le avec Tailwind, le styled de MUI, ou du CSS ordinaire. L'état de sélection reste le vôtre, exactement comme la démo ci-dessus le garde dans un seul useState.
L'accessibilité est presque gratuite — attention à deux lacunes
Comme la barre est un conteneur de défilement natif, le focus clavier, l'ordre de lecture du lecteur d'écran et le RTL viennent de la plateforme — déplacer le focus à travers les onglets les fait défiler dans la vue sans aucun code, et le RTL ne nécessite aucune configuration. Deux choses restent à votre charge, comme pour toute interface d'onglets : choisir votre motif ARIA (role="tablist" si de vrais panneaux basculent, aria-current si les « onglets » sont de la navigation), et conserver la suppression de clic de la recette de glisser pour défiler pour qu'un relâchement de glisser n'active jamais un onglet.
Le motif, minimal
Les onglets sont de simples boutons avec un itemId ; en sélectionner un le centre. C'est toute l'idée — la démo ci-dessus ajoute le style et le glisser.
function ScrollTabs({ tabs }: { tabs: string[] }) {
const [active, setActive] = React.useState(tabs[0]);
return (
<ScrollMenu LeftArrow={LeftArrow} RightArrow={RightArrow}>
{tabs.map((tab) => (
<Tab itemId={tab} key={tab} label={tab}
active={tab === active} onSelect={() => setActive(tab)} />
))}
</ScrollMenu>
);
}
function Tab({ itemId, label, active, onSelect }: TabProps) {
const api = React.useContext<publicApiType>(VisibilityContext);
return (
<button
aria-current={active}
onClick={(ev) => {
onSelect();
// The behavior that makes tabs feel native: selecting an
// edge tab glides it to the center of the strip.
api.scrollToItem(ev.currentTarget, 'smooth', 'center');
}}
>
{label}
</button>
);
}Ou installez-le comme composant shadcn
L'élément de registre scroll-tabs fournit ce motif piloté par les données — passez tabs, value, onValueChange — comme composant modifiable dans votre components/ui/ :
npx shadcn@latest add https://react-horizontal-scrolling-menu.dev/r/scroll-tabs.json