How to implement horizontal media scroller component in React with CSS only

bmstefanski

Bartłomiej Stefański

Posted on May 16, 2022

How to implement horizontal media scroller component in React with CSS only

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.

A preview of media scroller component

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>  
  );  
};
Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
bmstefanski
Bartłomiej Stefański

Posted on May 16, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related