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 = styled(Container)`
${down('sm')} {
max-width: 100%;
margin: unset;
padding: 0;
}
`;
const Grid = 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>
);
};
Top comments (0)