React component that implements drag-to-scroll functionality for content containers
npx @tessl/cli install tessl/npm-react-indiana-drag-scroll@2.2.0React Indiana Drag Scroll implements scroll on drag functionality for React applications. It enables users to scroll through content by clicking and dragging, similar to the scrolling behavior found in mobile applications or Adobe PDF viewers. The component provides comprehensive customization options for scrolling behavior, visual feedback, and interaction controls.
npm install react-indiana-drag-scrollimport ScrollContainer from "react-indiana-drag-scroll";
import { ScrollEvent } from "react-indiana-drag-scroll";For CommonJS:
const ScrollContainer = require("react-indiana-drag-scroll");import React from "react";
import ScrollContainer from "react-indiana-drag-scroll";
function App() {
return (
<ScrollContainer className="scroll-container">
<div style={{ width: "2000px", height: "1000px" }}>
{/* Your scrollable content here */}
<h1>Drag to scroll this large content area</h1>
</div>
</ScrollContainer>
);
}The main React component that wraps content to provide drag-to-scroll functionality.
export default class ScrollContainer extends React.PureComponent<ScrollContainerProps> {
/** Returns the HTML element of the scroll container */
getElement(): HTMLElement;
}Configuration options for the ScrollContainer component.
interface ScrollContainerProps {
/** Enable vertical drag scrolling (default: true) */
vertical?: boolean;
/** Enable horizontal drag scrolling (default: true) */
horizontal?: boolean;
/** Hide the scrollbars (default: true) */
hideScrollbars?: boolean;
/** Distance to distinguish click vs drag in pixels (default: 10) */
activationDistance?: number;
/** Content to be scrolled */
children?: ReactNode;
/** Callback when scrolling starts */
onStartScroll?: (event: ScrollEvent) => void;
/** Callback during scrolling */
onScroll?: (event: ScrollEvent) => void;
/** Callback when scrolling ends */
onEndScroll?: (event: ScrollEvent) => void;
/** Callback for click without drag */
onClick?: (event: MouseEvent) => void;
/** CSS class for container */
className?: string;
/** CSS class applied during dragging */
draggingClassName?: string;
/** Inline styles for container */
style?: CSSProperties;
/** CSS selector for elements to ignore dragging */
ignoreElements?: string;
/** Use native mobile scrolling on mobile devices (default: true) */
nativeMobileScroll?: boolean;
/** React ref */
ref?: ReactNode;
/** Root component type (default: 'div') */
component?: ElementType;
/** Alternative ref mechanism */
innerRef?: Ref<HTMLElement>;
/** Stop event propagation for mouse and touch events (default: false) */
stopPropagation?: boolean;
/** Mouse buttons that trigger scrolling (default: [0] - left button) */
buttons?: number[];
}Event object passed to scroll callback functions.
interface ScrollEvent {
/** Indicates if scroll was triggered externally (not by drag) */
external: boolean;
}Called when drag scrolling begins.
onStartScroll?: (event: ScrollEvent) => void;Called continuously during scrolling (both drag and native scroll events).
onScroll?: (event: ScrollEvent) => void;Called when scrolling stops (with debounce delay).
onEndScroll?: (event: ScrollEvent) => void;Control how far the mouse must move before drag scrolling activates:
<ScrollContainer activationDistance={20}>
{content}
</ScrollContainer>Show native scrollbars:
<ScrollContainer hideScrollbars={false}>
{content}
</ScrollContainer>Enable only horizontal or vertical scrolling:
{/* Horizontal only */}
<ScrollContainer vertical={false}>
{content}
</ScrollContainer>
{/* Vertical only */}
<ScrollContainer horizontal={false}>
{content}
</ScrollContainer>Prevent drag scrolling on certain elements:
<ScrollContainer ignoreElements="button, .modal, input">
<div>
<button>This won't trigger drag scroll</button>
<div className="modal">Neither will this</div>
</div>
</ScrollContainer>Configure which mouse buttons trigger scrolling:
{/* Right-click and middle-click scrolling */}
<ScrollContainer buttons={[1, 2]}>
{content}
</ScrollContainer>Use a different root element:
<ScrollContainer component="section" className="custom-scroll-section">
{content}
</ScrollContainer>Get the underlying HTML element:
import React, { useRef, useEffect } from "react";
import ScrollContainer from "react-indiana-drag-scroll";
function MyComponent() {
const scrollRef = useRef<ScrollContainer>(null);
useEffect(() => {
if (scrollRef.current) {
const element = scrollRef.current.getElement();
// Set initial scroll position
element.scrollLeft = 100;
element.scrollTop = 50;
}
}, []);
return (
<ScrollContainer ref={scrollRef}>
{content}
</ScrollContainer>
);
}Track scroll events with detailed callbacks:
import React from "react";
import ScrollContainer, { ScrollEvent } from "react-indiana-drag-scroll";
function ScrollableContent() {
const handleScrollStart = (event: ScrollEvent) => {
console.log("Scroll started", { external: event.external });
};
const handleScroll = (event: ScrollEvent) => {
console.log("Scrolling", { external: event.external });
};
const handleScrollEnd = (event: ScrollEvent) => {
console.log("Scroll ended", { external: event.external });
};
const handleClick = (event: MouseEvent) => {
console.log("Clicked without dragging");
};
return (
<ScrollContainer
onStartScroll={handleScrollStart}
onScroll={handleScroll}
onEndScroll={handleScrollEnd}
onClick={handleClick}
>
{content}
</ScrollContainer>
);
}The component applies several CSS classes for styling:
indiana-scroll-container - Base component classindiana-scroll-container--dragging - Applied during drag operationsindiana-scroll-container--hide-scrollbars - Applied when hideScrollbars is trueindiana-scroll-container--native-scroll - Applied on mobile devicesindiana-dragging - Added to document.body during dragCustom styling can be applied via the className, draggingClassName, and style props.
interface ScrollContainerProps {
vertical?: boolean;
horizontal?: boolean;
hideScrollbars?: boolean;
activationDistance?: number;
children?: ReactNode;
onStartScroll?: (event: ScrollEvent) => void;
onScroll?: (event: ScrollEvent) => void;
onEndScroll?: (event: ScrollEvent) => void;
onClick?: (event: MouseEvent) => void;
className?: string;
draggingClassName?: string;
style?: CSSProperties;
ignoreElements?: string;
nativeMobileScroll?: boolean;
ref?: ReactNode;
component?: ElementType;
innerRef?: Ref<HTMLElement>;
stopPropagation?: boolean;
buttons?: number[];
}
interface ScrollEvent {
external: boolean;
}