It is a common practice to render list in form of horizontal swipeable carousel on mobile resolutions. For that I created a simple, almost no-JS component for that. It uses JavaScript only for centering the overflow container.
I used styled-components and styled-breakpoints for this, but you can easily transform this to any other CSS-in-JS approach.
import { Container } from 'components/Container' ;
import { useEffect, useRef } from 'react' ;
import { down } from 'styled-breakpoints' ;
import styled from 'styled-components' ;
const GridContainer = withTheme (styled.Container)\ `
\$ {down('sm')} {
max-width: 100%;
margin: unset;
padding: 0;
}
\` );
const Grid = withTheme(styled.div<{ desktopMinWidth: string; mobileMinWidth: string }> \`
display: grid;
grid-template-columns: \$ {({ desktopMinWidth }) => \` )repeat(auto-fill, minmax( \$ {desktopMinWidth}, 1fr)) \` };
grid-gap: 18px;
\$ {down('sm')} {
padding: 0 20px;
position: relative;
cursor: grab;
scrollbar-width: none;
-ms-overflow-style: none;
::-webkit-scrollbar {
width: 0px;
background: transparent;
}
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
-webkit-overflow-scrolling: touch;
& > * {
min-width: \$ {({ mobileMinWidth }) => mobileMinWidth};
max-width: \$ {({ mobileMinWidth }) => mobileMinWidth};
scroll-snap-align: center;
}
}
\` ;
interface SwipeableGridProps {
mobileMinWidth: string;
desktopMinWidth: string;
children: React.ReactNode;
className?: string;
}
export const SwipeableGrid = ({
mobileMinWidth,
desktopMinWidth,
children,
className,
}: SwipeableGridProps) => {
const swipeableGridRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
const currentEl = swipeableGridRef.current;
if (currentEl) {
currentEl.scrollLeft = currentEl.clientWidth / 2;
}
}, []);
return (
<GridContainer>
<Grid
desktopMinWidth={desktopMinWidth}
mobileMinWidth={mobileMinWidth}
ref={swipeableGridRef}
className={className}
>
{children}
</Grid>
</GridContainer>
);
};