---
title: 'useOverflowScroll'
type: 'hook'
categories:
- Hooks
status: 'New'
designStatus: 'Done'
devStatus: 'Done'
notes: ''
---

A headless React hook that may be used as the foundation for building carousel-like UI components.

## Sample Usage

The following example demonstrates how to use `useOverflowScroll` to build a carousel-like UI component.

```jsx live
() => {
  const [overflowRef, setOverflowRef] = useState();

  const {
    isScrolledToStart,
    isScrolledToEnd,
    scrollToPrevious,
    scrollToNext,
  } = useOverflowScroll({
    childQuerySelector: '.example-item',
    overflowRef,
  });

  const ExampleItem = ({ className }) => (
    <div
      className={classNames('example-item border flex-shrink-0 text-center', className)}
      style={{ width: 160 }}
    >
      Item
    </div>
  );
  const itemCount = 20;
  const items = useMemo(() => Array.from({ length: itemCount }).map((index) => {
    if (index !== itemCount - 1) {
      return <ExampleItem key={uuidv4()} className="mr-2" />;
    }
    // last element, no right margin
    return <ExampleItem key={uuidv4()} />;
  }), []);

  return (
    <>
      <div className="mb-3">
        <Button
          onClick={scrollToPrevious}
          disabled={isScrolledToStart}
          size="sm"
          className="mr-2"
        >
          Previous
        </Button>
        <Button
          onClick={scrollToNext}
          disabled={isScrolledToEnd}
          size="sm"
        >
          Next
        </Button>
      </div>
      <div
        ref={setOverflowRef}
        aria-label="example overflow scroll container"
        className="d-flex"
      >
        {items}
      </div>
    </>
  );
};
```

The hook accepts the following options:
* `childQuerySelector`. A CSS query selector that can be used to find the child elements within the overflow container.
* `onScrollPrevious`. Supports a callback function when user scrolls to the previous element via a control.
* `onScrollNext`. Supports a callback function when user scrolls to the next element via a control.
* `hasInteractiveChildren`. Whether the child elements are interactive (e.g., clickable cards).
* `disableScroll`. An optional flag to disable the scroll behavior for the overflow container.
* `disableOpacityMasks`. An optional flag to disable the opacity masks at the start/end of the overflow container (if applicable).
* `scrollAnimationBehavior`. Allows overriding the default scroll behavior (e.g., "smooth", "instant", "auto").

The hook returns the following:
* Refs
  * `overflowRef`. The ref to pass to your overflow container. Note that this element may receive style overrides for `position: relative;` and `overflow-x: scroll` (optionally).
* Behaviors
  * `scrollToPrevious`. A click handler to scroll the overflow container to the previous element.
  * `scrollToNext`. A click handler to scroll the overflow container to the next element.
* Scroll state
  * `isScrolledToStart`. Whether the overflow container is scrolled to the start.
  * `isScrolledToEnd`. Whether the overflow container is scrolled to the end.
  * `activeChildElementIndex`. The index of the child element that is currently deemed to be "active", i.e. the child element used as the reference position for any `scrollToPrevious` or `scrollToNext` calls.

See [`OverflowScroll`](/components/overflowscroll/overflowscroll) for React components that encapsulate the logic within `useOverflowScroll`.

### Use of `offset` and `offsetType`

```jsx live
() => {
  const [offset, setOffset] = useState(50);
  const [offsetType, setOffsetType] = useState('percentage');

  const [overflowRef, setOverflowRef] = useState();

  const {
    isScrolledToStart,
    isScrolledToEnd,
    scrollToPrevious,
    scrollToNext,
  } = useOverflowScroll({
    childQuerySelector: '.example-item',
    overflowRef,
    offset,
    offsetType,
  });

  const ExampleItem = ({ className }) => (
    <div
      className={classNames('example-item border flex-shrink-0 text-center', className)}
      style={{ width: 160 }}
    >
      Item
    </div>
  );
  const itemCount = 20;
  const items = useMemo(() => Array.from({ length: itemCount }).map((index) => {
    if (index !== itemCount - 1) {
      return <ExampleItem key={uuidv4()} className="mr-2" />;
    }
    // last element, no right margin
    return <ExampleItem key={uuidv4()} />;
  }), []);

  return (
    <>
      {/* start example form block */}
      <ExamplePropsForm
        inputs={[
          {
            value: offset,
            setValue: setOffset,
            range: {
              min: 0,
              max: offsetType === 'percentage' ? 100 : 1000,
              step: offsetType === 'percentage' ? 1 : 50,
            },
            name: 'offset'
          },
          {
            value: offsetType,
            setValue: setOffsetType,
            options: ['percentage', 'fixed'],
            name: 'offsetType'
          },
        ]}
      />
      {/* end example form block */}

      <div className="mb-3">
        <Button
          onClick={scrollToPrevious}
          disabled={isScrolledToStart}
          size="sm"
          className="mr-2"
        >
          Previous
        </Button>
        <Button
          onClick={scrollToNext}
          disabled={isScrolledToEnd}
          size="sm"
        >
          Next
        </Button>
      </div>
      <div
        ref={setOverflowRef}
        aria-label="example overflow scroll container"
        className="d-flex"
      >
        {items}
      </div>
    </>
  );
};
```
