A React component to execute a function whenever you scroll to an element.

React Waypoint

A React component to execute a function whenever you scroll to an element. Works in all containers that can scroll, including the window.

React Waypoint can be used to build features like lazy loading content, infinite scroll, scrollspies, or docking elements to the viewport on scroll.

Inspired by Waypoints, except this little library grooves the Reactway.


View demo page



npm install react-waypoint --save


yarn add react-waypoint


import { Waypoint } from 'react-waypoint';


A waypoint normally fires onEnterand onLeaveas you are scrolling, but it can fire because of other events too:

  • When the window is resized
  • When it is mounted (fires onEnterif it's visible on the page)
  • When it is updated/re-rendered by its parent

Callbacks will only fire if the new position changed from the last known position. Sometimes it's useful to have a waypoint that fires onEnterevery time it is updated as long as it stays visible (e.g. for infinite scroll). You can then use a keyprop to control when a waypoint is reused vs. re-created.


Alternatively, you can also use an onPositionChangeevent to just get notified when the waypoint's position (e.g. inside the viewport, above or below) has changed.


Waypoints can take a child, allowing you to track when a section of content enters or leaves the viewport. For details, see Children, below.

<Waypoint onEnter={this._handleEnter}>
    Some content here

Example: JSFiddle Example

Prop types

propTypes: {

     * Function called when waypoint enters viewport
    onEnter: PropTypes.func,

     * Function called when waypoint leaves viewport
    onLeave: PropTypes.func,

     * Function called when waypoint position changes
    onPositionChange: PropTypes.func,

     * Whether to activate on horizontal scrolling instead of vertical
    horizontal: PropTypes.bool,

     * `topOffset` can either be a number, in which case its a distance from the
     * top of the container in pixels, or a string value. Valid string values are
     * of the form "20px", which is parsed as pixels, or "20%", which is parsed
     * as a percentage of the height of the containing element.
     * For instance, if you pass "-20%", and the containing element is 100px tall,
     * then the waypoint will be triggered when it has been scrolled 20px beyond
     * the top of the containing element.
    topOffset: PropTypes.oneOfType([

     * `bottomOffset` is like `topOffset`, but for the bottom of the container.
    bottomOffset: PropTypes.oneOfType([

     * Scrollable Ancestor - A custom ancestor to determine if the
     * target is visible in it. This is useful in cases where
     * you do not want the immediate scrollable ancestor to be
     * the container. For example, when your target is in a div
     * that has overflow auto but you are detecting onEnter based
     * on the window.
     * This should typically be a reference to a DOM node, but it will also work
     * to pass it the string "window" if you are using server rendering.
    scrollableAncestor: PropTypes.any,

     * fireOnRapidScroll - if the onEnter/onLeave events are to be fired
     * on rapid scrolling. This has no effect on onPositionChange -- it will
     * fire anyway.
    fireOnRapidScroll: PropTypes.bool,

     * Use this prop to get debug information in the console log. This slows
     * things down significantly, so it should only be used during development.
    debug: PropTypes.bool,

All callbacks (onEnter/onLeave/onPositionChange) receive an object as the only argument. That object has the following properties:

  • currentPosition- the position that the waypoint has at the moment. One of Waypoint.below, Waypoint.above, Waypoint.inside, and Waypoint.invisible.
  • previousPosition- the position that the waypoint had before. Also one of Waypoint.below, Waypoint.above, Waypoint.inside, and Waypoint.invisible.

In most cases, the above two properties should be enough. In some cases though, you might find these additional properties useful:

  • event- the native [scroll event]( that triggered the callback. May be missing if the callback wasn't triggered as the result of a scroll.
  • waypointTop- the waypoint's distance to the top of the viewport.
  • viewportTop- the distance from the scrollable ancestor to the viewport top.
  • viewportBottom- the distance from the bottom of the scrollable ancestor to the viewport top.

If you use es6 object destructuring, this means that you can use waypoints in the following way:

<Waypoint onEnter={({ previousPosition, currentPosition, event }) => {
    // do something useful!

If you are more familiar with plain old js functions, you'll do something like this:

<Waypoint onEnter={function(props) {
    // here you can use `props.currentPosition`, `props.previousPosition`, and
    // `props.event`

Offsets and Boundaries

Two of the Waypoint props are topOffsetand bottomOffset. To appreciate what these can do for you, it will help to have an understanding of the "boundaries" used by this library. The boundaries of React Waypoint are the top and bottom of the element containing your scrollable content (although this element can be configured). When a waypoint is within these boundaries, it is considered to be "inside." When a waypoint passes beyond these boundaries, then it is "outside." The onEnterand onLeaveprops are called as an element transitions from being inside to outside, or vice versa.

The topOffsetand bottomOffsetproperties can adjust the placement of these boundaries. By default, the offset is '0px'. If you specify a positive value, then the boundaries will be pushed inward, toward the center of the page. If you specify a negative value for an offset, then the boundary will be pushed outward from the center of the page.

Here is an illustration of offsets and boundaries. The black box is the scrollableAncestor. The pink lines represent the location of the boundaries. The offsets that determine the boundaries are in light pink.

Horizontal Scrolling Offsets and Boundaries

By default, waypoints listen to vertical scrolling. If you want to switch to horizontal scrolling instead, use the horizontalprop. For simplicity's sake, all other props and callbacks do not change. Instead, topOffsetand bottomOffset(among other directional variables) will mean the offset from the left and the offset from the right, respectively, and work exactly as they did before, just calculated in the horizontal direction.

Example Usage

Positive values of the offset props are useful when you have an element that overlays your scrollable area. For instance, if your app has a 50pxfixed header, then you may want to specify topOffset='50px', so that the onEntercallback is called when waypoints scroll into view from beneath the header.

Negative values of the offset prop could be useful for lazy loading. Imagine if you had a lot of large images on a long page, but you didn't want to load them all at once. You can use React Waypoint to receive a callback whenever an image is a certain distance from the bottom of the page. For instance, by specifying bottomOffset='-200px', then your onEntercallback would be called when the waypoint comes closer than 200 pixels from the bottom edge of the page. By placing a waypoint near each image, you could dynamically load them.

There are likely many more use cases for the offsets: be creative! Also, keep in mind that there are twoboundaries, so there are always twopositions when the onLeaveand onEntercallback will be called. By using the arguments passed to the callbacks, you can determine whether the waypoint has crossed the top boundary or the bottom boundary.


If you don't pass a child into your Waypoint, then you can think of the waypoint as a line across the page. Whenever that line crosses a boundary, then the onEnteror onLeavecallbacks will be called.

If you do pass a child, it can be a single DOM component (e.g. <div>) or a composite component (e.g. <MyComponent />).

Waypoint needs a DOM node to compute its boundaries. When you pass a DOM component to Waypoint, it handles getting a reference to the DOM node through the refprop automatically.

If you pass a composite component, you can wrap it with React.forwardRef(requires react@^16.3.0) and have the refprop being handled automatically for you, like this:

class Block extends React.Component {
  render() {
    return <div ref={this.props.innerRef}>Hello</div>

const BlockWithRef = React.forwardRef((props, ref) => {
  return <Block innerRef={ref} {...props} />

const App = () => (
    <BlockWithRef />

If you can't do that because you are using older version of React then you need to make use of the innerRefprop passed by Waypoint to your component. Simply pass it through as the refof a DOM component and you're all set. Like in this example:

class Block extends React.Component {
  render() {
    return <div ref={this.props.innerRef}>Hello</div>
Block.propTypes = {
  innerRef: PropTypes.func.isRequired,

const App = () => (
    <Block />

The onEntercallback will be called when anypart of the child is visible in the viewport. The onLeavecallback will be called when allof the child has exited the viewport.

(Note that this is measured only on a single axis. What this means is that for a Waypoint within a vertically scrolling parent, it could be off of the screen horizontally yet still fire an onEnter event, because it is within the vertical boundaries).

Deciding whether to pass a child or not will depend on your use case. One example of when passing a child is useful is for a scrollspy (like Bootstrap's). Imagine if you want to fire a waypoint when a particularly long piece of content is visible onscreen. When the page loads, it is conceivable that both the top and bottom of this piece of content could lie outside of the boundaries, because the content is taller than the viewport. If you didn't pass a child, and instead put the waypoint above or below the content, then you will not receive an onEntercallback (nor any other callback from this library). Instead, passing this long content as a child of the Waypoint would fire the onEntercallback when the page loads.

Containing elements and scrollableAncestor

React Waypoint positions its boundariesbased on the first scrollable ancestor of the Waypoint.

If that algorithm doesn't work for your use case, then you might find the scrollableAncestorprop useful. It allows you to specify what the scrollable ancestor is. Pass a reference to a DOM node as that prop, and the Waypoint will use the scroll position of thatnode, rather than its first scrollable ancestor.

This can also be the string "window", which can be useful if you are using server rendering.

Example Usage

Sometimes, waypoints that are deeply nested in the DOM tree may need to track the scroll position of the page as a whole. If you want to be sure that no other scrollable ancestor is used (since, once again, the first scrollable ancestor is what the library will use by default), then you can explicitly set the scrollableAncestorto be the windowto ensure that no other element is used.

This might look something like:



If your waypoint isn't working the way you expect it to, there are a few ways you can debug your setup.

OPTION 1: Add the debug={true}prop to your waypoint. When you do, you'll see console logs informing you about the internals of the waypoint.

OPTION 2: Clone and modify the project locally.

  • clone this repo
  • add console.logor breakpoints where you think it would be useful.
  • npm linkin the react-waypoint repo.
  • npm link react-waypointin your project.
  • if needed rebuild react-waypoint module: npm run build-npm


In this component we make a few assumptions that we believe are generally safe, but in some situations might present limitations.

  • We determine the scrollable-ness of a node by inspecting its computed overflow-y or overflow property and nothing else. This could mean that a container with this style that does not actually currently scroll will be considered when performing visibility calculations.
  • We assume that waypoints are rendered within at most one scrollable container. If you render a waypoint in multiple nested scrollable containers, the visibility calculations will likely not be accurate.
  • We also base the visibility calculations on the scroll position of the scrollable container (or windowif no scrollable container is found). This means that if your scrollable container has a height that is greater than the window, it might trigger onEnterunexpectedly.

In the wild

Organizations and projects using react-waypoint.


Credit to trotzigand lencionifor writing this component, and Brigadefor open sourcing it.

Thanks to the creator of the original Waypoints library, imakewebthings.



_Make sure to check out other popular open-source tools from the Brigade team: overcommitand haml-lint.





  • 高频数据交换下Flutter与ReactNative的对比

    (标题图片来自网络,侵删) 后端使用go写的socketio服务模拟期货行情数据,每10ms推送10条行情数据 ReactNative已经尽力优化了。 Flutter由于没fluttersock...

    2 年前
  • 高性能迷你React框架 anu1.3.0 发布

    anujs1.3.0是一款高性能Reactlike框架,是目前世界上对React16兼容最好的迷你库。 自React16起,相继推出createContext,createPortal, creat...

    2 年前
  • 高德地图 react-amap 实战

    clipboard.png( "clipboard.png") reacta...

    9 个月前
  • 高品质 React UI 组件


    2 年前
  • 骚操作!在react中使用vuex

    原文地址( 前言 笔者最近在学习使用,提到react就绕不过去。redux是一个状态管理架构,被广泛用于rea...

    2 年前
  • 项目文档说明:react + Ant Design 的 blog-react-admin

    效果图( "效果图") 前言 此 blogreactadmin 项目是基...

    2 年前
  • 面试题:Hooks 与 React 生命周期的关系

    React 生命周期很多人都了解,但通常我们所了解的都是 单个组件 的生命周期,但针对 Hooks 组件、多个关联组件(父子组件和兄弟组件) 的生命周期又是怎么样的喃?你有思考和了解过吗,接下来我们将...

    10 个月前
  • 面试官:请你在React中引入Vue3的@vue/reactivity,实现响应式。

    前言 React的状态管理是一个缤纷繁杂的大世界,光我知道的就不下数十种,其中有最出名immutable阵营的redux,有mutable阵营的mobx,reacteasystate,在hooks诞生...

    4 个月前
  • 面试官我想做个Reacter(React路由)

    路由的基础用法回顾,源码study,文章首发于docs,求个star 依赖 路由依赖于 reactrouter ,但是一般 pc 路由使用 reactrouterdom ,它依赖于 reactrout...

    3 个月前
  • 面试中React与Vue的比对

    1.virtual dom 用JS模拟DOM结构,DOM变化的对比,放在JS层做,以提高重绘性能 DOM操作昂贵,JS运行效率高,要减少DOM操作 使用:snabbdom的使用 ...

    2 年前


扫码加入 JavaScript 社区