A performant and comprehensive React sticky component.

Overview

react-stickynode

npm version Build Status Coverage Status

A performant and comprehensive React sticky component.

A sticky component wraps a sticky target and keeps the target in the viewport as the user scrolls the page. Most sticky components handle the case where the sticky target is shorter than the viewport, but not the case where a sticky target is taller than the viewport. The reason is that the expected behavior and implementation is much more complicated.

react-stickynode handles not only regular case but the long sticky target case in a natural way. In the regular case, when scrolling the page down, react-stickynode will stick to the top of the viewport. But in the case of a taller sticky target, it will scroll along with the page until its bottom reaches the bottom of the viewport. In other words, it looks like the bottom of viewport pulls the bottom of a sticky target down when scrolling the page down. On the other hand, when scrolling the page up, the top of viewport pulls the top of a sticky target up.

This behavior gives the content in a tall sticky target more chance to be shown. This is especially good for the case where many ADs are in the right rail.

Another highlight is that react-stickynode can handle the case where a sticky target uses percentage as its width unit. For a responsive designed page, it is especially useful.

Features

  • Retrieve scrollTop only once for all sticky components.
  • Listen to throttled scrolling to have better performance.
  • Use rAF to update sticky status to have better performance.
  • Support top offset from the top of screen.
  • Support bottom boundary to stop sticky status.
  • Support any sticky target with various width units.

Usage

The sticky uses Modernizr csstransforms3d and prefixed (link) features to detect IE8/9, so it can downgrade not to use transform3d.

import Sticky from 'react-stickynode';

<Sticky enabled={true} top={50} bottomBoundary={1200}>
    <YourComponent/>
</Sticky>
import Sticky from 'react-stickynode';

<Sticky top='#header' bottomBoundary='#content'>
    <YourComponent/>
</Sticky>

Props

Name Type Note
enabled Boolean The switch to enable or disable Sticky (true by default).
top Number/String The offset from the top of window where the top of the element will be when sticky state is triggered (0 by default). If it is a selector to a target (via querySelector()), the offset will be the height of the target.
bottomBoundary Number/String The offset from the top of document which release state will be triggered when the bottom of the element reaches at. If it is a selector to a target (via querySelector()), the offset will be the bottom of the target.
innerZ Number/String z-index of the sticky.
enableTransforms Boolean Enable the use of CSS3 transforms (true by default).
activeClass String Class name to be applied to the element when the sticky state is active (active by default).
innerClass String Class name to be applied to the inner element ('' by default).
className String Class name to be applied to the element independent of the sticky state.
releasedClass String Class name to be applied to the element when the sticky state is released (released by default).
onStateChange Function Callback for when the sticky state changes. See below.
shouldFreeze Function Callback to indicate when the sticky plugin should freeze position and ignore scroll/resize events. See below.

Handling State Change

You can be notified when the state of the sticky component changes by passing a callback to the onStateChange prop. The callback will receive an object in the format {status: CURRENT_STATUS}, with CURRENT_STATUS being an integer representing the status:

Value Name Note
0 STATUS_ORIGINAL The default status, located at the original position.
1 STATUS_RELEASED The released status, located at somewhere on document, but not default one.
2 STATUS_FIXED The sticky status, located fixed to the top or the bottom of screen.

You can access the statuses as static constants to use for comparison.

import Sticky from 'react-stickynode';

const handleStateChange = (status) => {
    if (status.status === Sticky.STATUS_FIXED) {
        console.log('the component is sticky');
    }
}

<Sticky onStateChange={handleStateChange}>
    <YourComponent/>
</Sticky>

Also Sticky supports children functions:

import Sticky from 'react-stickynode';

<Sticky>
  {status => {
    if (status.status === Sticky.STATUS_FIXED) {
      return 'the component is sticky';
    }
    if (status.status === Sticky.STATUS_ORIGINAL) {
      return 'the component in the original position';
    }
    return 'the component is released'
  }}
</Sticky>

Freezing

You can provide a function in the shouldFreeze prop which will tell the component to temporarily stop updating during prop and state changes, as well as ignore scroll and resize events. This function should return a boolean indicating whether the component should currently be frozen.

Install & Development

Install

npm install react-stickynode

Unit Test

npm run test

Linting

npm run lint

License

This software is free to use under the BSD license. See the LICENSE file for license text and copyright information.

Comments
  • Adding support for shouldFreeze hook

    Adding support for shouldFreeze hook

    Adding the ability to temporarily "turn off" a sticky node. This is intended to be different from the enabled prop, which resets the Sticky element - instead, this is a temporary disabling of the component so it doesn't respond to prop changes and scroll/resize events.

    Also switching the package used to test for prop and state changes, because is-equal-shallow is not suitable for testing props, which includes an object property (children) and thus will always cause isEqual() to return false. I'm open to using different methods for testing for prop changes however, or eliminating this check altogether if the perf impact isn't significant.

    opened by src-code 21
  • Adds onStickyStateChange callback function to props

    Adds onStickyStateChange callback function to props

    This callback will be fired when the sticky state of the component changes, and takes in an isSticky boolean which will be true if the current state is "sticky".

    opened by eligolding 18
  • Breaks building of a create-react-app application

    Breaks building of a create-react-app application

    Updating from 1.4.1 to 2.0.1 breaks the production build of an app created with create-react-app.

    The error lies in the subscribe-ui-event dependency.

    Failed to minify the code from this file:
    
            ./node_modules/subscribe-ui-event/dist-es/lib/listen.js:28
    
    Read more here: http://bit.ly/2tRViJ9
    
    opened by koox00 15
  • componentWillReceiveProps does not check props.enabled

    componentWillReceiveProps does not check props.enabled

    Steps to reproduce

    • Disable Sticky using the prop enabled={false}
    • Set up a component to receive other props (either by a re-render by parent) or dynamically changing some other prop on Sticky
    • Expectation: Methods like updateInitialDimension & update are not called due to the component being NOT enabled
    • Actual: When disabled, errors occur due to attempts to find the DOM node (or other issues) as the correct setup has not occurred.

    Receiving Error

    • Sticky.js:128 Uncaught TypeError: Cannot read property 'value' of null at Sticky.getBottomBoundary (Sticky.js:128) which maps to here https://github.com/yahoo/react-stickynode/blob/e4668b50226b8ebc78fe6ee4ff80d3423497a633/src/Sticky.jsx#L285
        componentWillReceiveProps (nextProps) {
            this.updateInitialDimension(nextProps);
            this.update();
        }
    

    Potential Fix

    • componentWillReceiveProps should check this.props.enabled before continuing and not call this.updateInitialDimension(nextProps); this.update(); if enabled is false
    • Similar to the checks in componentDidUpdate and componentDidMount
    opened by lb- 14
  • Refactor legacy code - use PureComponent instead of shallowCompare

    Refactor legacy code - use PureComponent instead of shallowCompare

    Easy refactoring and remove dependency.

    https://www.npmjs.com/package/react-addons-shallow-compare

    "react-addons-shallow-compare Note: This is a legacy React addon, and is no longer maintained.

    We don't encourage using it in new code, but it exists for backwards compatibility. The recommended migration path is to use React.PureComponent instead."

    opened by kunukn 14
  • Fork/rename this project

    Fork/rename this project

    Currently there's no one within Yahoo/Oath that has a desire to continue maintaining this project, so it'd be great if someone were to step forward and fork/rename this project and maintain it going forward so we can archive this repo.

    Anyone willing?

    cc @hankhsiao @roderickhsiao @markwoon @kunukn @aclimatt @redonkulus

    help wanted 
    opened by src-code 10
  • Sticky should sticky to another sticky

    Sticky should sticky to another sticky

    https://github.com/yahoo/react-stickynode/blob/master/src/Sticky.jsx#L292-L294

    If the top property refers to another Sticky instance, it should consider the offset of that Sticky instance together with its height.

    @hankhsiao

    opened by 100kV 10
  • Update refs element usage

    Update refs element usage

    Update refs usage to new api and don't use string refs

    https://reactjs.org/docs/refs-and-the-dom.html

    "Legacy API: String Refs If you worked with React before, you might be familiar with an older API where the ref attribute is a string, like "textInput", and the DOM node is accessed as this.refs.textInput. We advise against it because string refs have some issues, are considered legacy, and are likely to be removed in one of the future releases. If you’re currently using this.refs.textInput to access refs, we recommend the callback pattern instead."

    opened by kunukn 9
  • Call `update()` with new state from `componentWillReceiveProps()`

    Call `update()` with new state from `componentWillReceiveProps()`

    Hi,

    Every once in a while, we need to change props passed into react-stickynode (specifically in our case, top changes during runtime under various use cases). However right now, update() is called with the original state, not the result of any new props passed in. This runs update() with the result of the new props that are passed in, such that the position can be updated after the fact.

    We saw a different PR that tries to address a similar issue, https://github.com/yahoo/react-stickynode/pull/57 . However it seems to only address changing the targets. This seems like a slightly cleaner way to do it.

    I see the comment that "I believe one reason that the bottom and top boundary elements aren't able to be refreshed is because changing the boundaries after initial render can cause unexpected and undesirable rendering problems". I suppose I'm not sure what do to in this case; our implementation requires to update top at runtime, as others seem to do as well, and we haven't seen any unexpected behavior. But if you think that adding a note about potentially undesirable consequences should be added to the README, happy to do so! Just let me know.

    opened by aclimatt 8
  • accept props.innerZ to z-index the sticky

    accept props.innerZ to z-index the sticky

    I'm running into some issues with the styles where I need to have a z-index defined because I want the content to scroll underneath rather than over it (videoplayers). This allows us to pass a z for the inner element.

    @src-code

    opened by samlecuyer 8
  • Ignore scroll delta when adjusting for height changes

    Ignore scroll delta when adjusting for height changes

    There are certain scenarios where the sticky node becomes briefly but badly mispositioned because the height of a bottom-fixed sticky node changes while scroll events are still queued up. For example, if window.scrollTo() is used to scroll the document down immediately before unfreezing and updating the content of the sticky node, the scroll event will be handled much later (since it's throttled) and the resulting scroll delta will be applied to a node that's already being repositioned and released thanks to the height change, and so the node ends up repositioned well above where it should be.

    It seems incorrect and unnecessary to adjust for a scroll delta in the height-change code path, so this pull removes the subtraction of delta from the computation of stickyBottom in the case where the sticky node height has changed.

    FYI @roderickhsiao @hankhsiao

    opened by src-code 8
  • Fix react 18 failing test

    Fix react 18 failing test

    During React 18 testing one unit test was not passing, further debugging is required. The package was published to unblock users from upgrading to React 18. This bug could break your application!

    Issue when running the test:

    
      ● Sticky › should release when height gets changed (long Sticky)
    
        expect(received).toBe(expected) // Object.is equality
    
        Expected: "translate3d(0,1068px,0)"
        Received: "translate3d(0,-432px,0)"
    
           97 |     const style = t._style || t.style;
           98 |     expect(style.width).toBe('100px');
        >  99 |     expect(style.transform).toBe('translate3d(0,' + pos + 'px,0)');
              |                             ^
          100 |     expect(style.position).toBe('relative');
          101 |     expect(style.top).toBe('');
          102 | }
    
          at toBe (tests/unit/Sticky.test.js:99:29)
          at Object.shouldBeReleasedAt (tests/unit/Sticky.test.js:472:9)
    
    opened by redonkulus 0
  • feature-request: add width screen observer to automatically turn off the sticky effect

    feature-request: add width screen observer to automatically turn off the sticky effect

    if width reached the mobile/tablet viewport the sticky effect would immediately be turned off. we could pass as an option if they want the sticky effect is not to exist in the mobile viewport.

    I will file a PR in regard to this.

    opened by zourdyzou 0
  • Change architecture for functional components

    Change architecture for functional components

    The current project is using react components written in class form, which is already outdated and it is no longer advisable to write components this way. You can see more about it in this link.

    Changing components written in class to function format is a very important update to bring scalability, best practices and simpler refactoring to the project.

    So that future people in the community who want to contribute, but don't know this old format of creating react components, can also add to react-stickynode.

    Surely this is an important change for the future of the project in all aspects.

    opened by pauloreis7 5
  • Is core-js a dev dependency?

    Is core-js a dev dependency?

    Can we move core-js to devDependencies?

    Its currently conflicting with another lib I have which also uses core-js but another version.

    I believe if we move it to dev it will stop the problem.

    https://github.com/yahoo/react-stickynode/issues/324

    opened by pedroassis 8
  • Using same top and bottom boundary creates visual distortion

    Using same top and bottom boundary creates visual distortion

    If the top and bottom boundaries are the same then when you get to the bottom and want to scroll back to the top, it sticky will stay stuck to the bottom and essential scroll out of view as you return to the top. I assume it has to do with the top and bottom boundaries being the same name. The nav isn't as large as the content it scrolls with, and although it's redundant to use the same name for top and bottom (given a fixed height to account for the header could be applied), I figured maybe someone could use this scenario.

    opened by fnarbona 0
  • Large than viewport size sticky behavior affecting user experience

    Large than viewport size sticky behavior affecting user experience

    I am using the sticky to wrap a vertical left nav/sidebar menu, which has two parts which add up to be larger than viewport height. With the behavior described in the readme, it will scroll down until it reaches the bottom of the sticky. My menu is two parts; the first part has a menu that as you scroll will open automatically to the respective section of the documentation you are in, and the second part is just a list of all the different products we offer, which link to their specific documentation. I want to be able to have a fixed position until I am passed the first menu, then it can be free to scroll. Your behavior seems to be affecting this.

    opened by fnarbona 0
Releases(v4.1.0)
  • v4.1.0(Jul 15, 2022)

    Features

    • feat: support react 18 (#889). WARNING: This was published to unblock users from upgrading to React 18. An issue was created to track the failing test case https://github.com/yahoo/react-stickynode/issues/897

    Dependencies

    • chore(deps): bump core-js from 3.20.3 to 3.21.0 (#864) 6fff245
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0(Aug 11, 2021)

    Feature

    • feat: publish es modules (#554) 9634ffa

    Development

    • test: fix functional test flow (#543) 34efcc4

    Dependencies

    • chore(deps-dev): bump webpack from 5.49.0 to 5.50.0 (#552) 83d9174
    • chore(deps-dev): bump @babel/register from 7.14.5 to 7.15.3 (#553) bff5432
    • chore(deps-dev): bump @wdio/cli from 7.9.0 to 7.9.1 (#549) 302bde1
    • chore(deps-dev): bump @wdio/sauce-service from 7.9.0 to 7.9.1 (#547) ddeae6f
    • chore(deps): bump core-js from 3.16.0 to 3.16.1 (#548) 2292bd0
    • chore(deps-dev): bump @wdio/local-runner from 7.9.0 to 7.9.1 (#546) cbdc879
    • chore(deps-dev): bump @wdio/mocha-framework from 7.9.0 to 7.9.1 (#545) 9e4f0ae
    • chore(deps-dev): bump webpack from 5.48.0 to 5.49.0 (#544) 807740d
    • chore(deps-dev): bump @babel/preset-env from 7.14.9 to 7.15.0 (#542) b9f3376
    • chore(deps-dev): bump @babel/core from 7.14.8 to 7.15.0 (#541) a59b65d
    • chore: update package-lock.json format 43dc4f4

    https://github.com/yahoo/react-stickynode/compare/v3.1.1...v4.0.0

    Source code(tar.gz)
    Source code(zip)
  • v3.1.1(Aug 4, 2021)

  • v3.0.5(Mar 13, 2021)

  • v3.0.4(Oct 12, 2020)

  • v3.0.3(Jun 5, 2020)

  • v3.0.1(May 5, 2020)

  • v3.0.0(May 5, 2020)

  • v2.1.0(Oct 30, 2018)

  • v2.0.1(May 29, 2018)

  • v2.0.0(May 29, 2018)

    This release update the refs usage to the new api: https://reactjs.org/docs/refs-and-the-dom.html

    "Legacy API: String Refs If you worked with React before, you might be familiar with an older API where the ref attribute is a string, like "textInput", and the DOM node is accessed as this.refs.textInput. We advise against it because string refs have some issues, are considered legacy, and are likely to be removed in one of the future releases. If you’re currently using this.refs.textInput to access refs, we recommend the callback pattern instead."

    Thanks to @kunukn for contributing!

    Source code(tar.gz)
    Source code(zip)
  • v1.4.1(Jan 22, 2018)

  • v1.2.0(Aug 5, 2016)

  • v1.1.5(Jul 18, 2016)

    Switching to use react-addons-shallow-compare instead of is-equal-shallow, which tends to return false negatives for props. This should result in fewer unnecessary re-renders of the stickynode component, and so better performance.

    Source code(tar.gz)
    Source code(zip)
  • v1.1.4(Jul 15, 2016)

  • v1.1.3(Jun 17, 2016)

  • v1.1.2(Jun 2, 2016)

    If a scrollStart event is received but the scrollTop value doesn't seem to have changed from the cached value, skip handling the event and the subsequent scroll event. This fixes an issue seen when the document's scroll position is being restored (eg, during a page navigation event in a single page app) and sticky may incorrectly attempt to reposition itself due to the scroll event.

    Source code(tar.gz)
    Source code(zip)
  • v1.1.1(May 31, 2016)

  • v1.1.0(May 31, 2016)

  • v1.0.24(May 4, 2016)

  • v1.0.23(May 2, 2016)

  • v1.0.22(May 2, 2016)

  • v1.0.21(Apr 20, 2016)

  • v1.0.20(Apr 20, 2016)

  • v1.0.19(Apr 12, 2016)

Owner
Yahoo
Yahoo is a Verizon Media brand. This organization is the home to many of the active open source projects published by engineers at Yahoo and Verizon Media.
Yahoo
Delightful and highly customisable React Component to notify your users

react-notifications-component A delightful, easy to use and highly configurable component to help you notify your users out of the box. No messy setup

Rares Mardare 1.2k Dec 20, 2022
react-toasts is a very simple and lightweight component to create toasts.

Lightweight react toasts manager react-toasts is a very simple and lightweight component to create toasts. Demo url : https://vashnak.com/react-toasts

Anthony Sarais 57 Sep 16, 2022
Cross-platform Toast component for React Native, supports Android, IOS and Web

react-native-toast-notifications Toast component for React Native, supports Android, IOS and Web Features Fully Customizable Swipe to close support Sm

Alireza Rezania 411 Dec 28, 2022
React Toast Component - Custom push notification (Toast) implementation under React + stayed by TailwindCSS.

React Toast Component Online Demo Description This is custom toast component implemented by react hooks + React Context API and stayled using tailwind

Dalibor Kundrat 74 Dec 12, 2022
sAlert is a React component which provides alerts or notifications with rich configuration possibilities.

This lib is no longer maintained. It needs major adjustments and rewrites. I hope I'll find some time for it in the future. Sorry. React sAlert compon

Julian Ćwirko 658 Sep 6, 2022
A light-weight React toast component with extremely easy API.

Light Toast A light-weight React toast component with extremely easy API. Online Demo Installation yarn add light-toast Version 0.2.0 and above requir

Albert 58 Nov 30, 2022
React component with HTML5 Web Notification API

React component with HTML5 Web Notification API. This component show nothing in dom element, but trigger HTML5 Web Notification API with render method in the life cycle of React.js.

Mobilus Corporation 265 Dec 4, 2022
react-notification-timeline is a reactjs based component helps in managing the notifications in time-based manner

?? react-notification-timeline react-notification-timeline is a reactjs based component helps in managing the notifications in time-based manner. It i

Tapas Adhikary 117 Nov 9, 2022
A lightweight react toast notification component. 11 kb ~

React Toast Component A lightweight react toast notification component. 11 kb ~ Preview: Demo (npm: NPM github: Github) Installation Prerequisite: Rea

tumfoodery 4 Mar 26, 2022
A React component that notifies you when it enters or exits the viewport

A React component that notifies you when it enters or exits the viewport. Based on a IntersectionObserver, resulting in improved performance.

Veniamin Shitikov 10 Apr 15, 2022
React Native Clipboard API with Animated toast message component

react-native-clipboard-toast React Native Clipboard API with Animated toast message component Support both Android and iOS | Used react native Clipboa

Idan Levi 10 Sep 26, 2022
Beautiful, Zero Configuration, Toast Messages for React. Only ~ 4kb gzip, with styles and icons

Cogo Toast Beautiful, Zero Configuration, Toast Messages for React ~4kb gzip (with styles and icons) https://cogoport.github.io/cogo-toast/ Install vi

Cogoport 669 Dec 29, 2022
:postbox: A simple and customizable React notifications system

Reapop A simple and customizable React notifications system Summary Compatibility Demo Installation Integration & usage With React & Redux With React

Louis Barranqueiro 1.4k Dec 29, 2022
Spec compliant notifications for react and material ui users

react-materialui-notifications ❤️ the package? Then ⭐ it! Spec compliant notifications for react and material ui users Installation Use the latest git

Puranjay Jain 253 Dec 8, 2022
Alerts for react - Shows an alert in the position and for the duration specified.

react-alerts-plus Demo Shows an alert in the position and for the duration specified. You will most likely want to pass your own custom alert componen

Brian Andrews 6 Sep 6, 2022
Simple and lightweight toast package for React.js

Simple and lightweight toast package for React.js

Fuad Pashayev 11 Jul 7, 2022
This is a wrapper of the 'React' library 'React-Toastify' for usage in Shiny applications.

shinyToastify This is a wrapper of the 'React' library 'React-Toastify' for usage in Shiny applications. Six available types: The toast container and

null 9 Apr 28, 2022
Minimal toast notifications for React.

React Toast Minimal toast notifications for React. Get started Quick start Install with yarn yarn add react-toast Install with NPM npm install react-t

Mohammadreza Ziadzadeh 59 Jan 1, 2023
React notification made easy 🚀 !

React-Toastify ?? React-Toastify allows you to add notifications to your app with ease. No more nonsense! Installation $ npm install --save react-toas

Fadi Khadra 10.3k Jan 5, 2023