DEV Community

Bartłomiej Stefański
Bartłomiej Stefański

Posted on • Originally published at bstefanski.com on

3 3

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

Image of Datadog

Create and maintain end-to-end frontend tests

Learn best practices on creating frontend tests, testing on-premise apps, integrating tests into your CI/CD pipeline, and using Datadog’s testing tunnel.

Download The Guide

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay