Code Monkey home page Code Monkey logo

react-sticky-box's Introduction

Version Downloads/Week Minified Bundlesize Minified Gzipped Bundlesize

React Sticky Box

Sticky Boxes with sensible behaviour if the content is bigger than the viewport.

Documentation & Demo

react-sticky-box.codecks.io

Quick Start

Use as a Component

import StickyBox from "react-sticky-box";

const Page = () => (
  <div className="row">
    <StickyBox offsetTop={20} offsetBottom={20}>
      <div>Sidebar</div>
    </StickyBox>
    <div>Content</div>
  </div>
);

Or via the useStickyBox hook

import {useStickyBox} from "react-sticky-box";

const Page = () => {
  const stickyRef = useStickyBox({offsetTop: 20, offsetBottom: 20})
  <div className="row">
    <aside ref={stickyRef}>
      <div>Sidebar</div>
    </aside>
    <div>Content</div>
  </div>
};

Changelog

Contribute

  • checkout the repo
  • cd /path/to/repo/packages/docs
  • yarn install && yarn start

this will allow you to modify the react-sticky-box sources in packages/react-sticky-box/src and check the effects in the docs.

react-sticky-box's People

Contributors

a-ivanov81 avatar aaronlifton avatar andrenanninga avatar bordeo avatar danielberndt avatar dependabot[bot] avatar frntendev avatar jorgearanda avatar mdingena avatar oroce avatar patricksmith avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

react-sticky-box's Issues

React 17 support?

When installing in a react 17 library:

โฏ npm install react-sticky-box
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/react
npm ERR!   react@"^17.0.2" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^0.14.0 || ^15.0.0 || ^16.0.0" from [email protected]
npm ERR! node_modules/react-sticky-box
npm ERR!   react-sticky-box@"*" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See /Users/mf/.npm/eresolve-report.txt for a full report.

npm ERR! A complete log of this run can be found in:

Allow passing in custom `getScrollParent`

Problem

getScrollParent isn't working correctly for my particular use case:

  • My scroll container (overflow-y) is outside of my React app.
  • My React app isn't mounted in the DOM yet when getScrollParent runs.

(We're including the React app inside of a page written in a legacy framework. This problem occurs because of how we mount the React section of the page.)

Minimal working example

Fork of main example: https://codesandbox.io/s/x2kkkrjm8q

The relevant changes are:

  • Move .content-container out of <Page> and into index.html.
  • Render <Page> into a div that isn't in the DOM yet.
const div = document.createElement("div");
ReactDOM.render(<Page />, div);

const scrollContainer = document.querySelector(".content-container");
scrollContainer.appendChild(div);

Suggested solution

This is a pretty specific edge case that probably isn't worth supporting in this library. That said, I'd like the ability to pass in a custom getScrollParent implementation. Then I could do:

<StickyBox getScrollParent={() => document.getElementById('#scroll-container')}>

Sticky element position issue with dynamic pages

Hi, I use StickyBox to display filters for filtering the my page content. there is a case when StickyBox gets stuck outside it's container.
here is a sandbox for recreating this issue https://codesandbox.io/s/cool-darkness-hswks?file=/src/App.js

how to recreate:
1: scroll to footer
2: scroll up until both top and bottom edges of Stickybox are outside the screen.
3. press "remove" button to change page content
4. scroll up and down to see how it's stuck.

Clarification needed for browser support

The documentation is a little unclear about if this library will work as desired on browsers like IE.
It states that:

For all browsers without sticky support it falls back to a position: relative behaviour which should be a decent enough fallback in most cases.

This is slightly misleading as the definition of decent is subjective. Additionally it could be interpreted that this library falls back to position: relative; whilst also using a JavaScript implementation of the sticky effect as other libraries use.

Thanks

Recalculate StickyBox position with custom trigger

Can I force StickyBox to recalculate its top position?

I'm displaying an expandable list in a sidebar. When the list expands, the StickyBox sticks nicely when necessary. However, when I click the button at the bottom of the list to collapse it back into showing the top 10 items only, the StickyBox disappears off-screen. This is because the content is now much less high, and its top position is still offset from its longer previous height.

I'd like to be able to trigger a recalculation of the top position after collapsing my list. Is there a way to do that? I've thought about faking a browser window resize event, but that seems very dirty...

Allow both a top and bottom `offset` at the same time

The top offset is useful particularly when you also have a fixed navigation bar at the top of your page, so that your sidebar isn't partially hidden underneath it when it's sticky.

But what if I have both a fixed top and bottom bar? I've got a fixed navigation at the top of my page, and a fixed footer containing a music player.

I've partically solved this by giving the <StickyBox /> a child container with padding-bottom: 110px;. This makes sure that the sidebar's bottom content can be seen above the music player when the user still hasn't reached the end of the page.

But this introduces a new problem where when the user actually does reach the end of the page, the sidebar content starts to scroll up 110 pixels.

In an attempt to work around this, I've written a onChangeMode function that sets padding-bottom: 0 when oldMode was relative and newMode is stickyBottom. This works, but it results in jumpy behavior when scrolling back up (because the padding pops back in).

On a related issue, scrolling back up seems to always cause a tiny jump, which seems to be equal to offset={ 56 } in mix case. It seems there is some kind of "deadzone" that is related to the offset that is given to StickyBox.

At any rate, it would be very helpful if it was possible to give <StickyBox /> both a top and bottom offset, so we don't need these workarounds when dealing with fixed headers and footers.

Unable to use with Jest: `SyntaxError: Cannot use import statement outside a module`

I added this module to my project and it works, but tests began to fail:

    Details:

    /home/alex/Projects/soapbox-fe/node_modules/react-sticky-box/dist/index.js:2
    import React, { useEffect, useRef, useState } from "react";
    ^^^^^^

    SyntaxError: Cannot use import statement outside a module

      1 | import classNames from 'classnames';
      2 | import React from 'react';
    > 3 | import StickyBox from 'react-sticky-box';
        | ^
      4 |
      5 | const Layout: React.FC = ({ children }) => (
      6 |   <div className='sm:py-4 relative pb-36'>

      at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1728:14)
      at Object.<anonymous> (app/soapbox/components/ui/layout/layout.tsx:3:1)

Apparently Jest expects modules to be in CJS, and it simply will not work with ESM.

onChangeMode is invalid

Hi, I found the onChangeMode event only trigger once when the component is mount.
image
the element style is always position:sticky, is there anything wrong with me ? thanks

body overflow-x: hidden

Greetings, if i'm adding to body overflow-x: hidden, the sticky box stop working. Without it's working like a charm.

The Sticky box is in a deep nested Flex Layout.

Any ideas?

StickyBox data attributes should be transfers to created div container

Hi! Thank you for your project.
Can you please add data attributes transfer to StickyBox element?
For example, if you want to set data-testid on created by StickyBox div container probably the most intuitive way to do this is set it like this <StickyBox data-testid="some-testid" />.
But now you have to create another inner div element for this and add to it some css.

JSX Runtime.

Hi I am getting the following error inside a typescript project.

Error:
ERROR in ./node_modules/react-sticky-box/dist/index.js 3:0-40 Module not found: Error: Can't resolve 'react/jsx-runtime' in '../node_modules/react-sticky-box/dist' Did you mean 'jsx-runtime.js'? BREAKING CHANGE: The request 'react/jsx-runtime' failed to resolve only because it was resolved as fully specified (probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"'). The extension in the request is mandatory for it to be fully specified. Add the extension to the request.

I am using a sample from the demo site:
import StickyBox from "react-sticky-box"; <StickyBox offsetTop={90} offsetBottom={90}><div>Test</div></StickyBox>

Stickiness issue with css grid

Hi again,

I've been loving the work you're doing react-sticky-box and with the latest updates I've noticed such performance gains in the projects I've used it.

With that being said, I have found an issue regarding the use of react-sticky-box inside a css grid (display: grid);

Here it's a codesandbox with the issue detailed: https://codesandbox.io/s/p982r552lq

Basically, when the item's height increases to a value above the viewport height, the stickiness goes away and the item's position is reset to the position defined in the grid area.

onChangeMode not working

Hi! Huge fan of the library. Right now I'm trying to change the background color of the element when it's stuck. Everything works perfectly except I don't recieve callbacks when state changes

<StickyBox offsetTop={0} onChangeMode={(o, n) => console.log(o, n)}>

I get 3 logs onload, all undefined stickyTop - but then nothing.

HTML structure is quite simple:

Screen Shot 2021-01-21 at 5 55 34 PM

Responsive offset prop

I need to make the offset prop responsive in any way. I want the stickiness behaviour to be based on the height of 2 elements (header and subheader).

At the moment I'm trying to find a fixed value for the offset that works well across our supported devices.

The other quick solution, I have in mind is to have 2 separate sticky elements (one for desktop and one for tablet). I would really like to avoid doing this.

Thanks again for this awesome package. There are so few packages that deliver this in a small and convenient way. ๐Ÿ‘

1.0.1 does not work with react scripts 4.X

React-sticky-box 1.0.1 works fine when using react scripts 5.X

[...]
"react-scripts": "^5.0.0",
"react-sticky-box": "^1.0.1",
[...]

However, when using 4.X for react-scripts the import of react-sticky-box fails

[...]
"react-scripts": "^4.0.3",
"react-sticky-box": "^1.0.1",
[...]

import StickyBox from "react-sticky-box";

Module not found: Can't resolve 'react-sticky-box'

Any idea on how to resolve this issue? Upgrading to react-scripts is not really an option as it introduced major code breaks to many depending libraries.

License

Please add a license so that we can use this awesome lib. Thanks

getting error when trying to use the library

HI could you please help me I am trying to use the react-sticky-box but I am getting an error,
I have imported the library like this:
import StickyBox from "react-sticky-box/dist/esnext";

but I am getting the below error.

from UglifyJs Unexpected token: operator (>) [./~/react-sticky-box/dist/esnext/index.js:5,0]

how could I solve this?

thank you in advance

Inconsistent mode switching when using different scroll methods

After upgrading to 0.7.5 to fix #16, I ran a couple of tests and noticed that the "deadzone" issue is back (probably caused by the code changes from #25).

Upon further inspecting, I noticed that StickyBox behaves differently when dragging the scrollbar or when using the mouse wheel. I did that because I wanted to better inspect the "deadzone", a situation where you scroll in a direction but StickyBox remains sticky for some pixels.

Here's a screen recording of this behavior. Both sidebars are StickyBoxes.

https://i.imgur.com/3Zikt7b.gifv

Doesn't work

In this code it doesn't work: https://i.imgur.com/2dtQdih.png
Why? How to make it work?
I see you just apply the position sticky, right? But sticky can't work if an element is not in the body directly.

I've seen this on your website:

Make sure that the is only as high as its content, and not as high as the parent node...
Here is my website: https://i.imgur.com/kifESF8.jpg

Position is not recalculated on height change when in sticky mode

Hi! I've encountered a little problem.

Here's an example https://codesandbox.io/s/intelligent-brook-jq2xkp?file=/src/App.js

Try scrolling to the bottom of the sidebar (so that is becomes "sticky") and then click on the expand buttons.

Expected behavior: The sidebar that is sticky becomes relatively positioned and it's now possible to scroll down to the new bottom of the sidebar

Actual behavior:
1. It's not possible to scroll the sidebar further down to see the new content.
2. When you start scrolling the page iup, the sidebar snaps to the new bottom.

The same thing happens when the sidebar's height decreases. Try collapsing the expanded blocks when the sidebar is scrolled to its bottom and is "position: sticky"

Having issues with Server Side Rendering with Typescript

I have a types definition for react-sticky-box that look like this:

declare module 'react-sticky-box' {
    interface StickyBoxProps {
        bottom?: boolean;
        style?: React.CSSProperties;
        className?: string;
    }

    export default class StickyBox extends React.Component<StickyBoxProps> {}
}

However, when I go to render it with React.createFactory and ReactDOM.renderToNodeStream I end up with a ReactElement where the type is undefined:

{ '$$typeof': Symbol(react.element),
  type: undefined,
  key: '.0',
  ref: null,
  props:
   { className: 'sideNav',
     children:
      { '$$typeof': Symbol(react.element),
        type: [Object],
        key: null,
        ref: null,
        props: [Object],
        _owner: null,
        _store: {} } },
  _owner: null,
  _store: {} }

This results in errors that look like:

Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

I'm not sure if this is an issue with this library yet or my typings / imports but I'm trying to work it out. The weird thing is that the existing typings and code work in a storybook: I can see react-sticky-box working fine.

Trying to debug this now and any help would be great. Cheers.

'StickyBox' only refers to to a type

I'm using TypeScript 4.5 and Next.js 12 for this.

import StickyBox from "react-sticky-box"; using StickyBox as a component returns the following TypeScript error:
'StickyBox' only refers to a type, but is being used as a value here.

It works perfectly fine in my development environment, but once I go to production where type checking occurs in CI, the type checker will fail due to that error. My editor picks that up too.

This is probably a misconfiguration in the package for exporting the dist files which bundles fine, but confuses the type checker.

My current workaround is just using an @ts-ignore comment to skip type checking for that line.

handleScroll() null this object

Situation:

We recently incorporated this library, and our monitoring system (rollbar) began firing with issues like the this:
image

Our current hypothesis is that the scroll listener is fired after the object is already garbage collected, i.e. this is called after the object is removed: https://github.com/codecks-io/react-sticky-box/blob/master/src/index.js#L243

Expected:

(Assuming the listener is the issue) the listener would be removed before the object is cleaned up

Actual:

(Appears) the listener is not cleaned up.

Note:

Happy to open a PR for you to consider that adds the componentWillUnmount lifecycle method if that would be useful. The proposed change would be something like:

diff --git a/src/index.js b/src/index.js
index fb08721..5a095ec 100644
--- a/src/index.js
+++ b/src/index.js
@@ -57,6 +57,10 @@ export default class StickyBox extends React.Component {
     }
   }
 
+  componentWillUnmount(){
+    this.registerContainerRef(null);
+  }
+
   registerContainerRef = n => {
     if (!stickyProp) return;
     this.node = n;

Sticky box not working in IE

Hi,

It appears that the sticky box is not working in IE.

const StickyViewport = styled(StickyBox)
  display: flex;
  flex-direction: column;

  @media ${breakpoints.md}, ${breakpoints.lg} {
    height: 100vh;
  }
<StickyViewport>
    <ActivitiesStats activities={activities} examDate={examDate} getColor={getColor} />
    {(hasExamStats || hasQbankStats) && (
      <React.Fragment>
        <HSeparator />
        <GroupContainer>
          {hasExamStats && (
            <FlexItem grow={1}>
              <ExamStats exam={exam} getColor={getColor} />
            </FlexItem>
          )}
          {hasExamStats && hasQbankStats && <VSeparator />}
          {hasQbankStats && (
            <FlexItem grow={1}>
              <QbankStats qbank={qbank} getColor={getColor} />
            </FlexItem>
          )}
        </GroupContainer>
      </React.Fragment>
    )}
  </StickyViewport>

IE does not support sticky position.

screenshot_2

Is this a known bug?

Thanks!

Allow offsets in units other than pixels

Thanks for your work on this library! I would love to be able to specify offsetTop or offsetBottom in units other than pixels. As far as I can tell the offsets must be given as unit-less numbers (i.e. in pixels). I am trying to match another element in the page whose height is in em units (e.g., 3.25rem).

It would be nice if offsets could be specified in any CSS measurement unit.

change value of top: 0px

I need to make space from div header to StickyBox , i try to add style to <StickyBox style={{top:75}} but it doesn't work. i hope you will fix this. Thank you!

Allow user to set a custom container element of the sticky box

Right now you use <div> element as a container of the sticky box.

In a lot of cases the sticky box is a sidebar of a page and should be represented by <aside> element.

API could be:

<StickyBox as="aside" />

or something similar with as prop being by default <div>.

Detecting sticky section is applied

Hi,
I need to call a function when the section is sticky. Is there any way to detect whenever we have a sticky section at the top/bottom of a page?

Functions are not valid as a React

i was trying to install react-sticky-box with my react 18.2 ,next 13.0.2 project, i get errors

Warning: Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.
at div
at div
at div
at StickyBox (webpack-internal:///./node_modules/react-sticky-box/dist/index.js:258:20)

Layout broken in short viewport when changing scrollY

I noticed a layout bug with the sticky box. The sticky box did not detect the scrollY change, breaking the layout as shown in the preview.

To reproduce this:

  1. Resize the window to let the sticky box's height > viewport's height.
  2. scroll above the sticky box (make sure to scroll out of the sticky zone)
  3. click on a anchor tag to trigger a change in scrollY
react-sticky-box.Full.Page.Example.-.Google.Chrome.2023-12-04.13-55-39.mp4

Could this be fixed? Thanks, this is a useful library

offestTop has no effect

Im using the code below and the offset top has no effect. Am I using it wrong?

<section className="flex justify-center">
      <div className="w-full max-w-screen-2xl sm:w-5/6 flex items-start gap-10">
        {/* FIXME: Fix offsetTop not working */}
        <StickyBox offsetTop={100} offsetBottom={500}>
          <NewsNav newsItems={newsItems} />
        </StickyBox>
        <div className="w-full">
          {newsItems &&
            newsItems.map() => {
              return ....
            })}
        </div>
      </div>
</section>

Allow for offset

It may be the case that the user has a sticky header menu, for example, in which case the sticky elements shouldn't stick to the top of the page, but take that offset into consideration. Otherwise, it works great, thank you!

Sidebar height change => clicked area still visible

Hi,
is it possible to change this great sticky box behaviour a little?
Now when you expand sidebar and you're scrolled down, it changes to stickyBottom and content right after clicked button disappears:
image

But it would be nicer if sidebar stays "sticked" to top or relative, depends where you are. Like on this image:
image
So content of your sidebar don't hide outside of screen.

Changing this would make this sticky box more user friendly.

Non-sticky placement with large jumps in page

I have a StickyBox that is slightly larger than my window, and the content of the page is much longer than both the window and the StickyBox. I also have some buttons that allow me to scroll to different points on the page. These buttons use:

window.scrollTo({
  top: someYCoord,
  left: 0,
  behavior: "smooth"
})

...but some browsers, such as Safari, do not support smooth behaviour.

When I click on these buttons in Chrome/Firefox, the browser issues many scroll events, and the sticky box behaves as expected. But in Safari, the sticky box is not reliably sticky. The problem is that the StickyBox does not do full transitions between stickyTop and stickyBottom modes: it requires at least two scroll events to complete that transition, and Safari only issues one (very large) scroll event in the situation above.

One fix for this would be to have a custom trigger as mentioned in #16. But another is to modify the logic in handleScroll() to allow for transitions directly between stickyTop and stickyBottom modes through a single scroll event. I have a PR that does this and fixes the behaviour, and I'm pushing it shortly, but I wanted to document the bug I'm seeing first.

(Great library, by the way! Thanks for putting it out there)

Using with SSR

Hey,

first of all, thank you for making this component!

My question is, did you think about making this component work in server-side rendered apps? It breaks there because window object is not available, so I was thinking if we just added window && to this line if (window.CSS && window.CSS.supports) { it would work? What do you think? I can create a PR for that

Top offset isn't recalculated when content height has been changed

Hello! I found a strange behavior when using Sticky Box in my project. When you scroll down, the sticky gets position: relative and some top offset. After that I changed the content height. But the top offset was the same and sticky is partly out of parent.

Here is an example: scroll down the page, expand details, scroll down the page again and then collapse details. Result: the green border is out of black.

Sticky element is bigger than viewport

I'm having an issue, when the sticky element is bigger than the viewport and scrolling back up, instead of going back to top: 0px; it goes into a negative value like top: -77px;. The latter varies a lot depending on the height of both the sticky and the viewport or the scroll speed.

I'll attach a working example here

typeError when build in docker

This error only appeared in Docker environment

TypeError: Cannot read properties of null (reading 'useState')
2023-05-17 18:22:51     at exports.useState (/app/node_modules/react/cjs/react.production.min.js:25:394)
2023-05-17 18:22:51     at useStickyBox (file:///app/node_modules/react-sticky-box/dist/index.js:239:27)
2023-05-17 18:22:51     at StickyBox (file:///app/node_modules/react-sticky-box/dist/index.js:252:15)
2023-05-17 18:22:51     at Ge (/app/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.production.min.js:114:273)
2023-05-17 18:22:51     at Z (/app/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.production.min.js:120:91)
2023-05-17 18:22:51     at He (/app/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.production.min.js:123:155)
2023-05-17 18:22:51     at Ge (/app/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.production.min.js:115:215)
2023-05-17 18:22:51     at Z (/app/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.production.min.js:120:91)
2023-05-17 18:22:51     at He (/app/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.production.min.js:123:155)
2023-05-17 18:22:51     at Je (/app/node_modules/next/dist/compiled/react-dom/cjs/react-dom-server.browser.production.min.js:122:100)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.