react-scrollbars-custom

2020-02-14

react-scrollbars-custom

The best React custom scrollbars component

react-scrollbars-custom

× DEMO× LIVE EXAMPLE× CHANGELOG×


  • Native browser scroll behavior - it don't emulate scrolling, only showing custom scrollbars, scrolling itself still native
  • Cross-browser and cross-platform - does not matter where and how, scrollbars looks the same everywhere
  • Ultimate performance - 60 FPS (using RAF) and highly optimised code
  • No extra stylesheets required - minimum inline styles out of the box or you can style it yourself however you want
  • Fully customizable - want a hippo as a scrollbar thumb? Well.. I don't judge you, you're free to do it!
  • Scrollbars nesting
  • Total tests coverage
  • Momentum scrolling for iOS
  • RTL support (read more)
  • Content sizes translation (read more)
  • Proper page zoom handling (native scrollbars does not show up)

INSTALLATION

npm install react-scrollbars-custom
# or via yarn
yarn add react-scrollbars-custom

INSTALLATION NOTE:This lib is written in ES6+ and delivering with both, transpiled and untranspiled versions:

  • mainfield of package.jsonis pointing to transpiled ES3-compatible version with CJS modules resolution;
  • modulefield is pointing to transpiled ES3-compatible version with ES modules resolution;
  • esnextfield is pointing to the ES6+ version with ES modules resolution;

Depending on your targets you may have to use Webpackand/or Babelto pull untranspiled version of package. See some tips on wiring thing up: https://2ality.com/2017/06/pkg-esnext.html

USAGE

Underneath react-scrollbars-customuses requestAnimationFrameloop, which check and update each known scrollbar, and as result - scrollbars updates synchronised with browser's render flow. The <Scrollbar />component works out of the box, with only need of widthand heightto be set, inline or via CSS;

<Scrollbar style={{ width: 250, height: 250 }}>
  <p>Hello world!</p>
</Scrollbar>

Internet Explorer

react-scrollbars-customis syntax-compatible with IE10, but you'll have to use polyfills - for example @babel/polyfill.

Styling

Probably you'll wish to customize your scrollbars on your own way via CSS - then simply pass noDefaultStylesprop - it will prevent all inline styling from appear. But some of styles will remain due to their need for proper component work.

Native mode

One more pretty common need is to disable custom scrollbars and fallback to native ones, it can be done by passing nativeprop. It'll change the generated markup:

// scrollbar.scrollerElement
<div class="ScrollbarsCustom native trackYVisible trackXVisible">
  // scrollbar.contentElement - the one that holds tour content
  <div class="ScrollbarsCustom-Content">
    // YOUR CONTENT IS HERE
  </div>
</div>

As you see here - now the root element has the scrollerElementref, but otherwise its treated as a before (as holder). contentElementbehaves as it was before.

Content sizes translation

In some situations you may want to make the scrollbars block of variable sizes - just pass translateContentSize*ToHolderprop and component will automatically translate corresponding contentElement's sizes to the holderElement. If you are using default styles - it'll be handy to pass compensateScrollbarsWidth={false}props, to avoid infinite shrinking when it's not supposed to. Note:This wont work for native mode.

RTL support

react-scrollbars-customsupports RTL direction out of the box, you don't have to pass extra parameters to make it work, it'll be detected automatically on first component's render. But you still able to override it through the prop. There are several things you have to know about:

  • Due to performance reasons direction autodetect happens is 3 cases:
    • On component mount;
    • On rtl property change;
    • On state isRtlset to non-boolean value;
  • rtlproperty has priority over the styleor CSS properties;
  • If rtlprop has not been set (undefined) - direction will be detected automatically according to content element's CSS;
  • If rtlprop is true- direction: rtl;style will be applied to hte content element;
  • If rtlprop is false- no style will be applied to holder;

Customisation

In some cases you may want to change the default className or tagName of elements or add extra markup or whatever. For these purposes react-scrollbars-custommade fully customizable. You can do absolutely what ever you want y simply passing renderer SFC to the needed props.

IMPORTANT: Renderer will receive elementRef function that expect the DOM element's reference as first parameter. Furthermore you have to pass the styles, cause they needed to proper component work.

<Scrollbar
  renderer={props => {
    const { elementRef, ...restProps } = props;
    return <span {...restProps} ref={elementRef} className="MyAwesomeScrollbarsHolder" />;
  }}
  wrapperProps={{
    renderer: props => {
      const { elementRef, ...restProps } = props;
      return <span {...restProps} ref={elementRef} className="MyAwesomeScrollbarsWrapper" />;
    }
  }}
  scrollerProps={{
    renderer: props => {
      const { elementRef, ...restProps } = props;
      return <span {...restProps} ref={elementRef} className="MyAwesomeScrollbarsScroller" />;
    }
  }}
  contentProps={{
    renderer: props => {
      const { elementRef, ...restProps } = props;
      return <span {...restProps} ref={elementRef} className="Content" />;
    }
  }}
  trackXProps={{
    renderer: props => {
      const { elementRef, ...restProps } = props;
      return <span {...restProps} ref={elementRef} className="TrackX" />;
    }
  }}
  trackYProps={{
    renderer: props => {
      const { elementRef, ...restProps } = props;
      return <span {...restProps} ref={elementRef} className="trackY" />;
    }
  }}
  thumbXProps={{
    renderer: props => {
      const { elementRef, ...restProps } = props;
      return <span {...restProps} ref={elementRef} className="ThUmBX" />;
    }
  }}
  thumbYProps={{
    renderer: props => {
      const { elementRef, ...restProps } = props;
      return <span {...restProps} ref={elementRef} className="tHuMbY" />;
    }
  }}
/>

Generated HTML

// scrollbar.holderElement
<div class="ScrollbarsCustom trackYVisible trackXVisible">
  // scrollbar.wrapperElement - the one that hiding native scrollbars
  <div class="ScrollbarsCustom-Wrapper">
    // scrollbar.scrollerElement - the one that actually has browser's scrollbars
    <div class="ScrollbarsCustom-Scroller">
      // scrollbar.contentElement - the one that holds tour content
      <div class="ScrollbarsCustom-Content">
        // YOUR CONTENT IS HERE
      </div>
    </div>
  </div>
  // scrollbar.trackYElement
  <div class="ScrollbarsCustom-Track ScrollbarsCustom-TrackY">
    // scrollbar.thumbYElement
    <div class="ScrollbarsCustom-Thumb ScrollbarsCustom-ThumbY" />
  </div>
  // scrollbar.trackXElement
  <div class="ScrollbarsCustom-Track ScrollbarsCustom-TrackX">
    // scrollbar.thumbXElement
    <div class="ScrollbarsCustom-Thumb ScrollbarsCustom-ThumbX" />
  </div>
</div>
  • If scrolling is possible or tracks are shown die to permanentScrollbar*prop - trackYVisible/trackXVisibleclassnames are applied to the holder element.
  • When thumb is dragged it'll have draggingclassname.
  • If direction is RTL - rtlclassname will be added to the holder element.
  • By default whole structure described above is rendered in spite of tracks visibility, but it can be changed by passing removeTrackXWhenNotUsed/removeTrackYWhenNotUsed/removeTracksWhenNotUsedprops to the component. Respective tracks will not be rendered if it is unnecessary.

API

PROPS

You can pass any HTMLDivElement props to the component - they'll be respectfully passed to the holder element/renderer.

createContext:boolean= undefined Whether to create context that will contain scrollbar instance reference.

rtl:boolean= undefined true- set content's direction RTL, false- LTR, undefined- autodetect according content's style.

native:boolean= undefined Do not use custom scrollbars, use native ones instead.

mobileNative:boolean= undefined As nativebut enables only on mobile devices (actually when the scrollbarWidthis 0).

momentum:boolean= true Whether to use momentum scrolling, suitable for iOS (will add -webkit-overflow-scrolling: touchto the content element).

noDefaultStyles:boolean= undefined Whether to use default visual styles. Note:Styles needed to proper component work will be passed regardless of this option.

disableTracksMousewheelScrolling:boolean= undefined Disable content scrolling while preforming a wheel event over the track.

disableTrackXMousewheelScrolling:boolean= undefined Disable content scrolling while preforming a wheel event over the track.

disableTrackYMousewheelScrolling:boolean= undefined Disable content scrolling while preforming a wheel event over the track.

disableTracksWidthCompensation:boolean= undefined Disable both vertical and horizontal wrapper indents that added in order to not let tracks overlay content. Note:Works only with default styles enabled.

disableTrackXWidthCompensation:boolean= undefined Disable horizontal wrapper indents that added in order to not let horizontal track overlay content. Note:Works only with default styles enabled.

disableTrackYWidthCompensation:boolean= undefined Disable vertical wrapper indents that added in order to not let vertical track overlay content. Note:Works only with default styles enabled.

minimalThumbSize:number= 30 Minimal size of both, vertical and horizontal thumbs. This option has priority to minimalThumbXSize/minimalThumbYSizeprops.

maximalThumbSize:number= undefined Maximal size of both, vertical and horizontal thumbs. This option has priority to maximalThumbXSize/maximalThumbYSizeprops.

minimalThumbXSize:number= undefined Minimal size of horizontal thumb.

maximalThumbXSize:number= undefined Maximal size of horizontal thumb.

minimalThumbYSize:number= undefined Minimal size of vertical thumb.

maximalThumbYSize:number= undefined Maximal size of vertical thumb.

noScroll:boolean= undefined Whether to disable both vertical and horizontal scrolling.

noScrollX:boolean= undefined Whether to disable horizontal scrolling.

noScrollY:boolean= undefined Whether to disable vertical scrolling.

permanentTracks:boolean= undefined Whether to display both tracks regardless of scrolling ability.

permanentTrackX:boolean= undefined Whether to display horizontal track regardless of scrolling ability.

permanentTrackY:boolean= undefined Whether to display vertical track regardless of scrolling ability.

removeTracksWhenNotUsed:boolean= undefined Whether to remove both vertical and horizontal tracks if scrolling is not possible/bocked and tracks are not permanent.

removeTrackYWhenNotUsed:boolean= undefined Whether to remove horizontal track if scrolling is not possible/bocked and tracks are not permanent.

removeTrackXWhenNotUsed:boolean= undefined Whether to remove vertical track if scrolling is not possible/bocked and tracks are not permanent.

translateContentSizesToHolder:boolean= undefined Pass content's scrollHeightand scrollWidthvalues to the holder's heightand widthstyles. Not working with nativebehavior.

translateContentSizeYToHolder:boolean= undefined Pass content's scrollHeightvalues to the holder's heightstyle. Not working with nativebehavior.

translateContentSizeXToHolder:boolean= undefined Pass content's scrollWidthvalues to the holder's widthstyle. Not working with nativebehavior.

trackClickBehavior:string= "jump" The way scrolling behaves while user clicked the track:

  • jump- will cause straight scroll to the respective position.
  • step- will cause one screen step towards (like PageUp/PageDown) the clicked position.

scrollbarWidth:number= undefined Scrollbar width value needed to proper native scrollbars hide. While undefinedit is detected automatically (once per module require). This prop is needed generally for testing purposes.

fallbackScrollbarWidth:number= 20 This value will be used in case of falsy scrollbarWidthprop. E.g. it is used for mobile devices, because it is impossible to detect their real scrollbar width (due to their absolute positioning).

scrollTop:number= undefined Prop that allow you to set vertical scroll.

scrollLeft:number= undefined Prop that allow you to set horizontal scroll.

scrollDetectionThreshold:number= 100 Amount of seconds after which scrolling will be treated as completed and scrollStopevent emitted.

elementRef:function(ref: Scrollbar)= undefined Function that receive the scrollbar instance as 1st parameter.

renderer:SFC= undefined SFC used to render the holder. More about renderers usage.

wrapperProps:object= {} Here you can pass any props for wrapper, which is usually HTMLDivElement plus elementRefprops which behaves as holder's elementRefprop.

contentProps:object= {} Here you can pass any props for content, which is usually HTMLDivElement plus elementRefprops which behaves as holder's elementRefprop.

trackXProps:object= {} Here you can pass any props for trackX, which is usually HTMLDivElement plus elementRefprops which behaves as holder's elementRefprop.

trackYProps:object= {} Here you can pass any props for trackY, which is usually HTMLDivElement plus elementRefprops which behaves as holder's elementRefprop.

thumbXProps:object= {} Here you can pass any props for thumbX, which is usually HTMLDivElement plus elementRefprops which behaves as holder's elementRefprop.

thumbYProps:object= {} Here you can pass any props for thumbY, which is usually HTMLDivElement plus elementRefprops which behaves as holder's elementRefprop.

onUpdate:function(scrollValues: ScrollValues, prevScrollValues: ScrollValues)= undefined Function called each time any of scroll values changed and component performed an update. It is called after component's update.

onScroll:function(scrollValues: ScrollValues, prevScrollValues: ScrollValues)= undefined Function called each time scrollTop or scrollLeft has changed. It is called after component's update and even if scrollTop/scrollLeft has been changed through the code (not by user).

onScrollStart:function(scrollValues: ScrollValues)= undefined Callback that called immediately when user started scrolling (no matter how, thumb dragging, keyboard, mousewheel and etc.).

onScrollStop:function(scrollValues: ScrollValues)= undefined Callback that called after props.scrollDetectionThresholdmilliseconds after last scroll event.

INSTANCE PROPERTIES

eventEmitter:EmittrEvent emitter that allow you to add events handler for cases when you access Scrollbars through context

holderElement:HTMLDivElement | nullHolder DOM element reference or null if element was not rendered

wrapperElement:HTMLDivElement | nullWrapper DOM element reference or null if element was not rendered

scrollerElement:HTMLDivElement | nullScroller DOM element reference or null if element was not rendered

contentElement:HTMLDivElement | nullContent DOM element reference or null if element was not rendered

trackXElement:HTMLDivElement | nullHorizontal track DOM element reference or null if element was not rendered

trackYElement:HTMLDivElement | nullVertical track DOM element reference or null if element was not rendered

thumbXElement:HTMLDivElement | nullHorizontal thumb DOM element reference or null if element was not rendered

thumbYElement:HTMLDivElement | nullVertical thumb DOM element reference or null if element was not rendered

(get|set) scrollTop:numberContent's element scroll top

(get|set) scrollLeft:numberContent's element scroll left

(get) scrollHeight:numberContent's element scroll height

(get) scrollWidth:numberContent's element scroll width

(get) clientHeight:numberContent's element client height

(get) clientWidth:numberContent's element client width

INSTANCE METHODS

getScrollState(force:boolean = false):plain objectCurrent scroll-related values, if forceparameter is falsy - returns cached value which updated with RAF loop Returned values:

type ScrollState = {
  /**
   * @description Content's native clientHeight parameter
   */
  clientHeight: number;
  /**
   * @description Content's native clientWidth parameter
   */
  clientWidth: number;
  /**
   * @description Content's native scrollHeight parameter
   */
  scrollHeight: number;
  /**
   * @description Content's native scrollWidth parameter
   */
  scrollWidth: number;
  /**
   * @description Content's native scrollTop parameter
   */
  scrollTop: number;
  /**
   * @description Content's native scrollLeft parameter
   */
  scrollLeft: number;
  /**
   * @description Indicates whether vertical scroll blocked via properties
   */
  scrollYBlocked: boolean;
  /**
   * @description Indicates whether horizontal scroll blocked via properties
   */
  scrollXBlocked: boolean;
  /**
   * @description Indicates whether the content overflows vertically and scrolling not blocked
   */
  scrollYPossible: boolean;
  /**
   * @description Indicates whether the content overflows horizontally and scrolling not blocked
   */
  scrollXPossible: boolean;
  /**
   * @description Indicates whether vertical track is visible
   */
  trackYVisible: boolean;
  /**
   * @description Indicates whether horizontal track is visible
   */
  trackXVisible: boolean;
  /**
   * @description Indicates whether display direction is right-to-left
   */
  isRTL?: boolean;

  /**
   * @description Pages zoom level - it affects scrollbars
   */
  zoomLevel: number;
};

scrollToTop():thisScroll to the very top border of scrollable area

scrollToLeft():thisScroll to the very left border of scrollable area

scrollToBottom():thisScroll to the very bottom border of scrollable area

scrollToRight():thisScroll to the very right border of scrollable area

scrollTo(x?: number, y?: number):thisSet the current scroll at given coordinates. If any value is undefinedit'll be left as is.

centerAt(x?: number, y?: number):thisCenter viewport at given coordinates. If any value is undefinedit'll be left as is.

以上是 react-scrollbars-custom 的使用教程帮助文档。


上一篇:@babel/plugin-transform-exponentiation-operator
下一篇:@babel/plugin-transform-property-literals
相关教程
关注微信

扫码加入 JavaScript 社区

相关文章

首次访问,需要验证
微信扫码,关注即可
(仅需验证一次)

欢迎加入 JavaScript 社区

号内回复关键字:

回到顶部