Introducing PrimeReact v11-alpha 🎉Discover Now

useScrollArea

Hook that manages custom scrollbar state, overflow detection, and thumb positioning.

basic-demo

Usage#

import { useScrollArea } from '@primereact/headless/scrollarea';
 
const { rootProps, viewportProps, contentProps, scrollbarYProps, thumbYProps, hiddenState } = useScrollArea();
 
return (
    <div {...rootProps}>
        <div {...viewportProps} style={{ overflow: 'scroll', scrollbarWidth: 'none' }}>
            <div {...contentProps}></div>
        </div>
        {!hiddenState.y && (
            <div {...scrollbarYProps}>
                <div {...thumbYProps} />
            </div>
        )}
    </div>
);

useScrollArea manages custom scrollbar state, thumb positioning, and overflow detection — see Primitive for a component-based API.

Features#

  • Returns spread-ready prop objects with built-in ref callbacks for all scroll area elements
  • Automatic thumb size calculation based on viewport-to-content ratio
  • Pointer-based drag handling for both scrollbar track and thumb
  • ResizeObserver-based recalculation on content changes
  • Overflow edge detection (scrollXBefore, scrollXAfter, scrollYBefore, scrollYAfter)
  • Support for both vertical and horizontal scrolling

Behavior#

Variant#

Use variant to control scrollbar visibility behavior.

const scrollArea = useScrollArea({ variant: 'hover' });

Available values: 'auto' (default), 'hover', 'scroll', 'always', 'hidden'.

Hidden State#

hiddenState provides boolean flags that indicate whether each scrollbar and the corner should be rendered.

const { hiddenState } = useScrollArea();
 
// hiddenState.x      → true when horizontal scrollbar is unnecessary
// hiddenState.y      → true when vertical scrollbar is unnecessary
// hiddenState.corner → true when the corner element is unnecessary (at least one axis has no overflow)

Use these flags for conditional rendering of scrollbar and corner elements.

Corner Size#

cornerSize exposes the measured dimensions of the corner area where both scrollbars intersect. The hook sets --corner-width and --corner-height CSS variables on the root automatically, but cornerSize provides direct access for layout calculations.

const { cornerSize } = useScrollArea();
 
// cornerSize.width  → pixel width of the vertical scrollbar (0 when no corner)
// cornerSize.height → pixel height of the horizontal scrollbar (0 when no corner)

Overflow Detection#

state provides fine-grained scroll position flags for building fade masks, shadow indicators, or loading triggers at content edges.

const { state } = useScrollArea();
 
// state.hasOverflowX  → true when content overflows horizontally
// state.hasOverflowY  → true when content overflows vertically
// state.scrollYBefore → true when scrolled past the top edge
// state.scrollYAfter  → true when content remains below the viewport
// state.scrollXBefore → true when scrolled past the left edge
// state.scrollXAfter  → true when content remains to the right

Both Scrollbars#

For content that overflows in both directions, use orientation-specific prop objects for each scrollbar and thumb. The corner element fills the intersection.

const { scrollbarYProps, scrollbarXProps, thumbYProps, thumbXProps, cornerProps, hiddenState } = useScrollArea();
 
{
    !hiddenState.y && (
        <div {...scrollbarYProps}>
            <div {...thumbYProps} />
        </div>
    );
}
{
    !hiddenState.x && (
        <div {...scrollbarXProps}>
            <div {...thumbXProps} />
        </div>
    );
}
{
    !hiddenState.corner && <div {...cornerProps} />;
}

Thumb Positioning#

The hook sets CSS custom properties on scrollbar elements for thumb dimensions and positioning:

VariableDescription
--thumb-heightCalculated thumb height (vertical bar)
--thumb-widthCalculated thumb width (horizontal bar)
--thumb-offsetCalculated thumb offset along the track

Apply these via inline styles on the thumb element:

<div style={{ height: 'var(--thumb-height)', transform: 'translate3d(0, var(--thumb-offset, 0), 0)' }} />

Custom Styling with Data Attributes#

Every prop object includes data-scope="scrollarea" and a data-part attribute for targeted CSS selectors.

[data-scope='scrollarea'][data-part='scrollbar-y'] {
    width: 8px;
}
 
[data-scope='scrollarea'][data-part='thumb-y'] {
    background: rgba(0, 0, 0, 0.3);
    border-radius: 4px;
}

API#

useScrollArea#

NameTypeDefault
stepnumber5
Step factor to scroll the content while pressing the arrow keys.
variant"hidden" | "auto" | "always" | "scroll" | "hover"'auto'
Controls scrollbar visibility behavior.

Accessibility#

See ScrollArea Primitive for WAI-ARIA compliance details and keyboard support.