Pestañas de React que se desplazan como el navegador
Una barra de pestañas deja de caber en cuanto tu producto supera las seis pestañas. La solución no es una fuente más pequeña: es una barra que se desplaza. El desbordamiento lo gestiona el navegador, al hacer clic en una pestaña esta se centra y las flechas aparecen solo cuando hay a dónde ir.
Haz clic en una pestaña cerca del borde: se desplaza sola hasta el centro.
Edita este ejemplo en vivo en Storybook
El único comportamiento que importa: centrar al seleccionar
Una barra de pestañas desplazable vive o muere por lo que pasa al hacer clic en una pestaña del borde: debería deslizarse hasta el centro y revelar sus vecinas a ambos lados. Aquí es una sola llamada —scrollToItem(el, 'smooth', 'center')— conectada en el ejemplo de centrar al hacer clic. Restaurar la pestaña activa al montar es la misma llamada con 'auto', mostrada en guardar y restaurar posición.
Las flechas vienen de los mismos datos de visibilidad: useLeftArrowVisible es falso solo mientras la primera pestaña está fuera de pantalla, así que la flecha izquierda se renderiza justo cuando es útil. Sin código de medición propio, sin observadores de resize propios.
Si te estás quedando corto con las pestañas desplazables de MUI
Las pestañas variant="scrollable" de Material UI son la respuesta correcta dentro del sistema de diseño de Material, hasta que tus "pestañas" dejan de ser pestañas. MUI suelda la barra a la semántica de Tabs: un par value/onChange, paneles de pestaña y botones de scroll que MUI oculta en móvil por defecto. En el momento en que tu fila contiene chips, tarjetas, avatares o contenido mixto, o necesita arrastre para desplazar, o necesita saber qué elementos están visibles, estás luchando contra el componente en lugar de usarlo.
Esta librería es la capa de debajo: una fila con scroll y seguimiento de visibilidad, sin opinión sobre qué es una "pestaña". Tu pestaña es cualquier componente con un itemId: dale estilo con Tailwind, con el styled propio de MUI o con CSS normal. El estado de selección sigue siendo tuyo, igual que la demo de arriba lo guarda en un único useState.
La accesibilidad sale casi gratis: cuidado con dos huecos
Como la barra es un contenedor de scroll nativo, el foco de teclado, el orden de lectura del lector de pantalla y RTL vienen de la plataforma: mover el foco entre pestañas las desplaza a la vista sin escribir código, y RTL no necesita configuración. Dos cosas siguen dependiendo de ti, igual que en cualquier UI de pestañas: elegir tu patrón ARIA (role="tablist" si de verdad cambian paneles, aria-current si las "pestañas" son navegación) y mantener la supresión de clic de la receta de arrastre para desplazar para que soltar un arrastre nunca active una pestaña.
El patrón, en su forma mínima
Las pestañas son botones normales con un itemId; seleccionar una la centra. Esta es toda la idea: la demo de arriba añade estilos y arrastre.
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>
);
}O instálalo como componente shadcn
El elemento del registro scroll-tabs distribuye este patrón basado en datos —pasa tabs, value, onValueChange— como componente editable en tu components/ui/:
npx shadcn@latest add https://react-horizontal-scrolling-menu.dev/r/scroll-tabs.jsonEjemplos relacionados
- Centrar el elemento clicadoscrollToItem con inline: center — el patrón de pestañas desplazables.
- Guardar y restaurar la posición de desplazamientoMantén el desplazamiento entre desmontajes y recargas de página.
- Arrastrar para desplazarse con el ratónArrastre con el ratón que sigue dejando funcionar los clics.