Skip to content

useReel

Edit on GitHub
@volvo-cars/react-headless v0.24.7

Manages horizontal scrolling reel/carousel components with snap points and navigation.

import { useRef } from 'react';
import { useReel } from '@volvo-cars/react-headless';
function Reel() {
const ref = useRef<HTMLDivElement>(null);
const {
activeIndex,
totalCount,
previousButtonProps,
nextButtonProps,
reelProps,
} = useReel({ ref });
return (
<div>
<div ref={ref} className="reel" {...reelProps}>
<div className="reel-frame">Frame 1</div>
<div className="reel-frame">Frame 2</div>
<div className="reel-frame">Frame 3</div>
</div>
<div className="flex items-center gap-8">
<button {...previousButtonProps}>Previous</button>
<span>
{activeIndex + 1} / {totalCount}
</span>
<button {...nextButtonProps}>Next</button>
</div>
</div>
);
}

The hook returns previousButtonProps and nextButtonProps that should be spread onto your navigation buttons. These props include onClick handlers, disabled state, and accessibility attributes — the buttons are hidden from assistive technology since the scroll container itself is keyboard-navigable.

import { useRef } from 'react';
import { useReel } from '@volvo-cars/react-headless';
function ReelWithNavigation() {
const ref = useRef<HTMLDivElement>(null);
const { previousButtonProps, nextButtonProps, reelProps } = useReel({ ref });
return (
<div>
<div ref={ref} className="reel" {...reelProps}>
<div className="reel-frame">Frame 1</div>
<div className="reel-frame">Frame 2</div>
<div className="reel-frame">Frame 3</div>
</div>
<button {...previousButtonProps}>←</button>
<button {...nextButtonProps}>→</button>
</div>
);
}

Use the onChange callback to react when the visible frame changes:

import { useRef } from 'react';
import { useReel } from '@volvo-cars/react-headless';
function ReelWithCallback() {
const ref = useRef<HTMLDivElement>(null);
const { reelProps } = useReel({
ref,
onChange: ({ activeIndex, target }) => {
console.log('Now viewing frame', activeIndex, target);
},
});
return (
<div ref={ref} className="reel" {...reelProps}>
<div className="reel-frame">Frame 1</div>
<div className="reel-frame">Frame 2</div>
<div className="reel-frame">Frame 3</div>
</div>
);
}

The hook automatically sets tabIndex={0} on the reel container if it contains no focusable children, ensuring keyboard users can scroll the reel. The navigation buttons are hidden from screen readers (aria-hidden) since the scroll container is already keyboard-navigable.

useReel accepts an options object with the following properties:

  • ref – ref to the scrollable container element (required)
  • onChange – callback fired when the active index changes, receives { activeIndex, target, currentTarget }

The hook returns an object with:

  • activeIndex – the index of the first visible frame
  • totalCount – the total number of frames in the reel
  • reelProps – props to spread on the reel container (includes tabIndex when needed)
  • previousButtonProps – props to spread on the “previous” navigation button (includes onClick, disabled, and ARIA attributes)
  • nextButtonProps – props to spread on the “next” navigation button (includes onClick, disabled, and ARIA attributes)