React Scroll Box
Note I'm currently working on [email protected]
. 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.
Contents
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
fortextarea
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
.
ScrollAxes axes = ScrollAxes.XY
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.
FastTrack fastTrack = FastTrack.GOTO
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 genericScrollBox
Reference toGenericScrollBox
that is being scrolled.
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 totrue
to prevent invocation ofonViewportScroll
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 totrue
to prevent invocation ofonViewportScroll
until requested scrolling is finished. Can be used for synchronization of multiple scroll areas.
License
The code is available under MIT licence.