javascriptreactjsreact-hooks

React scroll component horizontally on button click


I am currently building a card section which shows a horizontal list of cards. This list overflows, which makes the user have to scroll horizontally to view the offscreen cards.

To make this process easier for the user, I want to create buttons which scroll the horizontal list to the left or right.

I tried solving this by creating a reference to the horizontal list and apply a scrollX when I click on the previously mentioned button. This however, results in the following error:

Cannot add property scrollX, object is not extensible

My code:

const ref = useRef(null);

const scroll = () => {
  ref.scrollX += 20;
};

return (
  <div className={style.wrapper} id={id}>
    <Container className={style.container}>
      <Row>
        <Col>
          <button onClick={scroll}>TEST</button>
        </Col>
      </Row>
    </Container>
    <div className={style.projects} ref={ref}>
      {projects.map((data, index) => (
        <CardProject
          key={index}
          title={data.title}
          image={data.image}
          description={data.description}
        />
      ))}
    </div>
  </div>
);

Solution

  • In order to access a DOM Node with a Ref, you need to use ref.current; useRef is a container for a DOM node and you access that node with the current property.

    Additionally, scrollX is a read-only property; you need to call scrollLeft to change the scroll position. For scrollLeft to work, you need to add an overflow-x: scroll; rule to the style.projects for it to work. (If style.projects is an object than change to overflowX: 'scroll'.)

    To be able to scroll left or right, your can add a parameter to the function for the scroll offset, so it doesn't always scroll right:

    const scroll = (scrollOffset) => {
      ref.current.scrollLeft += scrollOffset;
    };
    

    For this to work, you'll need two buttons in your JSX that pass in the offset values for left or right to the scroll function:

     <Row>
            <Col>
              <button onClick={() => scroll(-20)}>LEFT</button>
              <button onClick={() => scroll(20)}>RIGHT</button>
            </Col>
      </Row>