/react-scroll-box

Charged cross-browser and cross-platform scrollable container implementation with no external dependencies but React 0.13+.

Primary LanguageJavaScriptMIT LicenseMIT

React Scroll Box

npm version

Note I'm currently working on resct-scroll-box@0.3. It would contain 50+ configurable paramters and would provide fine grained tracking of scrolling events and their causes.

Charged cross-browser and cross-platform scrollable container implementation with no external dependencies but React 0.13+.

Requires classList polyfill to work properly in IE9+.

Tested in FF, Chrome, Safari, iOS Safari, Opera and IE9+.

Any help with improvement of this component would be greatly appreciated.

API Playground and Live Demo

Contents

  1. Motivation
  2. ScrollBox
  3. Attributes
  4. GenericScrollBox
  5. Layout
  6. Properties
  7. Methods
  8. License

Motivation

  • Use custom or native scroll bars.
  • Highly customizable tracks and handles for both mobile and desktop.
  • Inset and outset scroll bars with ease.
  • Optional fallback to native inertial scrolling on mobile devices.
  • Animated and smooth scrolling with customizable easing functions.
  • Scrollbars detect mouse in close proximity and change their style accordingly for better UX.
  • Scrollbars are automatically added, removed and resized when scroll box dimensions are changed.
  • Scrolling speed is equalized among browsers.
  • Customizable keyboard scrolling support.
  • Scroll boxes can be nested.
  • Custom viewports can be used. Have a look at react-text-input for textarea with customizable scrollbars.
  • Conditionally unwrap scroll box to scroll its content along with page. This can even be done using a media query.
  • Scrollbar size represents ratio of content and viewport sizes and can be constrained from CSS.
  • LESS styles with a mixin to simplify coloring.
  • Lots of other properties to customize scrolling behavior.

ScrollBox

In most cases you should use ScrollBox to create a scrollable area, but in case you need more control over viewport use GenericScrollBox.

By default, ScrollBox has no decoration and behaves as a regular div container. Specify height for scroll box in your styles, otherwise container would contract to zero height.

var ScrollBox = require('react-scroll-box').ScrollBox; // ES5

import {ScrollBox, ScrollAxes, FastTrack} from 'react-scroll-box'; // ES6

<ScrollBox style={{height: '200px'}} axes={ScrollAxes.Y} fastTrack={FastTrack.PAGING}>
  Place any content here.
</ScrollBox>

Attributes

boolean nativeScroll

Use native scrollbars. By default, this flag is set to true on mobile platforms and false on desktops. Paltforms are distinguished by presence of window.orientation.

Scroll axes which are managed by the scroll box. If scroll axis is not listed then corresponding scroll offset would be constantly equal to 0 and any scrolling requests via API or from UI for that axes would be ignored.

integer hoverProximity = 50

Maximum distance in pixels between cursor and scroll track edge when track is considered to be hovered. Useful when you want to have thin scrollbars and increase theit thickness when cursor aproaches them so user don't have to aim precisely. Set to 0 to disable hover proximity detection.

boolean disabled = false

Disable scroll box.

boolean outset = false

Display scrollbars outside of scrollable area. Outset scrllbars don't require additional space and don't affect surrounding layout. On mobile devices when native scrollbars are used this property has no effect because scrollbars have zero width and thus don't crop any space from viewport.

integer scrollMinX = 2 scrollMinY = 2

Minimum difference in pixels in content and viewport sizes to enable scrolling.

boolean captureKeyboard = true

Use keyboard for scrolling when scroll box viewport or its nested content is focused. Keyboard is not captured for <input type="text"/> and <textarea/> elements placed inside scroll box. PgUp PgDown Home End and arrow keys are captured. You can page-scroll alternate axis with Shift + PgUp and Shift + PgDown shortcuts.

integer keyboardStepX = 30 keyboardStepY = 30

Distance in pixels to scroll by when arrow keys are pressed.

integer keyboardScrollDuration = 200

Keyboard smooth scrolling animation duration in milliseconds. Set to 0 to disable smooth keyboard scrolling.

Defines expected behavior when user clicks on scroll track.

integer fastTrackDuration = 500

Animation duration of fast track smooth scroll.

boolean captureHandleDrag = true

Allow user to drag scroll handles. If handle drag is disabled along with enabled fast track then clicking on a handle would cause fast tracking.

boolean captureWheel = true

Use mouse wheel for scrolling. You can scroll alternate axis with Shift key is pressed.

integer wheelStepX = 30 wheelStepY = 30

Wheel scrolling distance in pixels. Scroll box heavily relies on native wheel implementation, so this speed can vary a bit depending on browser, platform and scrolling device (trackpad or mouse wheel).

boolean propagateWheelScroll = false

Propagate wheel scroll event to parent if scrolling reached maximum or minimum value.

boolean swapWheelAxes = false

Swap wheel scrolling axes.

integer wheelScrollDuration = 100

Wheel smooth scrolling animation duration. Set to 0 to disable smooth wheel scrolling.

string className = "scroll-box--wrapped"

Style class name to use.

object style

Style to apply to root element of scroll box.

function defaultEasing (percent, elapsed, min, max, duration)

Easing to use when none is provided.

  • float percent Scroll percentage in range [0, 1].
  • integer elapsed Number of milliseconds passed since animation began.
  • integer min max Output value range.
  • integer duration Animation duration in milliseconds.

function onViewportScroll (genericScrollBox)

Scroll event callback.

GenericScrollBox

Expects viewport element at its only child. Has all the same attributes as ScrollBox.

var GenericScrollBox = require('react-scroll-box').GenericScrollBox; // ES5

import {GenericScrollBox, ScrollAxes, FastTrack} from 'react-scroll-box'; // ES6

<GenericScrollBox style={{height: '200px'}} axes={ScrollAxes.Y} fastTrack={FastTrack.PAGING}>
  <div className="scroll-box__viewport">
    Place any content here.
  </div>
</GenericScrollBox>

Layout

<div class="scroll-box scroll-box--wrapped">
  <div class="scroll-box__track scroll-box__track--x">
    <div class="scroll-box__handle scroll-box__handle--x"></div>
  </div>
  <div class="scroll-box__track scroll-box__track--y">
    <div class="scroll-box__handle scroll-box__handle--y"></div>
  </div>
  <div class="scroll-box__viewport">
    Place any content here.
  </div>
</div>
Class Name Description
scroll-box--wrapped Causes scroll box to look like an actual scroll box. If omitted, then scrollbox behaves like a simple div element.
scroll-box--disabled Scroll box is disabled. By default, hides scrollbars and prevents scrolling.
scroll-box--native Display native scroll bars.
scroll-box--outset Show scroll bars ouside of scrollable area.
scroll-box--has-axis-x Scroll box can be scrolled horizintally if content is wider than viewport.
scroll-box--has-axis-y Scroll box can be scrolled vertically if content is taller than viewport.
scroll-box--show-axis-x Content is wider than viewport.
scroll-box--show-axis-y Content is taller than viewport.
scroll-box__track--hover Tack is hovered.
scroll‑box__track‑‑dragged Track handle is dragged.

Modifier .scroll-box--wrapped-on-large-screens would conditionally wrap scroll box on screens larger than 360 px. Content would be scrolled along with page itself on smaller screens.

@media (min-width: 360px) {
  .scroll-box--wrapped-on-large-screens {
    .scroll-box-wrap();
  }
}

Properties

HTMLDivElement handleX handleY

Handle elements. Both are always available, even if axes exclude one or both of them.

HTMLDivElement trackX trackY

Track elements. Both are always available.

HTMLElement viewport

Viewport element provided to GenericScrollBox.

integer targetX targetY

Scroll position in pixels that was last requested.

integer previousX previousY

Previously requested scroll position.

integer scrollX scrollX

Actual scroll position that user observes. This changes repeatedly during scroll animation, when no animation is in proggress equals to targetX and targetY respectively.

integer scrollMaxX scrollMaxY

Maximum values for horizontal and vertical content scroll positions. See MDN window.scrollMaxX for more info.

integer trackMaxX trackMaxY

Maximum values for horizontal and vertical track scroll positions. When nativeScroll is set to true these are constanly equal to 0.

boolean exposesX exposesY

Does scroll box require actual presence of horizontal or vertical scroll bars. If set to true, then axis is permitted via props.axes and corresponding scrollMax is greater or equal to scrollMin.

Methods

void scrollBy(dx, dy, duration, easing, silent)

Scroll by the given amount of pixels.

  • integer dx = 0 dy = 0 Amount of pixels to scroll by. Positive coordinates will scroll to the right and down the content. Negative values will scroll to the left and up the content. If non-numeric value are provided then corresponding position of scroll bar coordinate is not changed.
  • integer duration = 0 Duration of scrolling animation.
  • function easing = defaultEasing Scroll easing function.
  • boolean silent = false Set to true to prevent invocation of onViewportScroll until requested scrolling is finished. Can be used for synchronization of multiple scroll areas.

void scrollTo(x, y, duration, easing, silent)

Scroll to arbitrary content position.

  • integer x = undefined y = undefined Position to scroll to. If non-numeric value are provided then corresponding position of scroll bar coordinate is not changed.
  • integer duration = 0 Duration of scrolling animation.
  • function easing = defaultEasing Scroll easing function.
  • boolean silent = false Set to true to prevent invocation of onViewportScroll until requested scrolling is finished. Can be used for synchronization of multiple scroll areas.

License

The code is available under MIT licence.