Git Product home page Git Product logo

pettiboy / react-ui-scrollspy Goto Github PK

View Code? Open in Web Editor NEW
80.0 2.0 10.0 14.25 MB

Customizable Scroll Spy component for react which is Simple, Easy To Use and Lightweight with callback, typescript, auto-update URL hash and throttle support among others.

Home Page: https://pettiboy.github.io/react-ui-scrollspy/

License: MIT License

HTML 23.07% TypeScript 69.61% CSS 5.86% JavaScript 1.46%
react reactjs typescript scroll-events scroll-spy scrolling component react-component react-scrollspy react-scrollspy-component

react-ui-scrollspy's Introduction

ScrollSpy Demo

React UI ScrollSpy

npm npm License MIT PRs Welcome

React TypeScript NPM

Make sure you ⭐️ this repository if you find it helpful or interesting :)

✨ Installation

React 18

npm install --save react-ui-scrollspy

OR

yarn add react-ui-scrollspy

React 17 and below

npm install --save [email protected]

OR

🎞 Demo

Try it your self here!

Demo 1 Demo 2
ScrollSpy Demo ScrollSpy Demo

⚙️ Usage

  1. In your navigation component
<div>
  <p data-to-scrollspy-id="first">Section 1</p>
  <p data-to-scrollspy-id="second">Section 2</p>
</div>
  1. Wrap the elements you want to spy on in the <ScrollSpy> component.
import ScrollSpy from "react-ui-scrollspy";

<ScrollSpy>
  <div id="first">
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Aut dolores
    veritatis doloremque fugit. Soluta aperiam atque inventore deleniti,
    voluptatibus non fuga eos magni natus vel, rerum excepturi expedita.
    Tempore, vero!
  </div>
  <div id="second">
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Aut dolores
    veritatis doloremque fugit. Soluta aperiam atque inventore deleniti,
    voluptatibus non fuga eos magni natus vel, rerum excepturi expedita.
    Tempore, vero!
  </div>
</ScrollSpy>
  1. Write styles for when the navigation element which is active in your index.css
.active-scroll-spy {
  background-color: yellowgreen;
  border-radius: 15px;
}

📝 Notes

Incase the ScrollSpy is not working the way you expected, you can try the following:

  • Reduce the value of scrollThrottle.

  • If your page contains a navbar a header consider adding the following CSS

html {
  scroll-padding-top: 120px; /* height of your navbar */
}

💡 Props

🔧 Children

Attributes Type Description Default Required
children ReactNode Each direct child Element should contain an id - yes

🔧 Refs

Attributes Type Description Default Required
navContainerRef MutableRefObject
<HTMLDivElement | null>
ref to your navigation container containing items with data-to-scrollspy-id attributes - no
parentScrollContainerRef MutableRefObject
<HTMLDivElement | null>
If you want to spy only on a particular scrollable container (Element) then pass its ref to this prop - no

🔧 Throttle

Attributes Type Description Default Required
scrollThrottle number In milliseconds to throttle the onscroll event. Lower the number, better the response time, higher the performance cost 300 no

🔧 Callback

Attributes Type Description Default Required
onUpdateCallback (id: string) => void Executes this function whenever you scroll to a new ScrollSpy child Element, callback returns the id of that Element as well - no

🔧 Offsets

Attributes Type Description Default Required
offsetTop number Spy will be fired when it has been scrolled offsetTop beyond 50% to the top of the containing element 0 no
offsetBottom number Spy will be fired when it has been scrolled offsetBottom beyond 50% to the bottom of the containing element 0 no

🔧 Customize Attributes

Attributes Type Description Default Required
useDataAttribute string To customize the string after data- "to-scrollspy-id" no
activeClass string To customize the class added when the Element in view "active-scroll-spy" no
useBoxMethod boolean Set to false if you want your spy to be active only if more than 50% of that div is in the viewport true no
updateHistoryStack boolean Set to false to disable the URL getting automatically updated when scrolling true no

📝 Authors

react-ui-scrollspy's People

Contributors

guilhermeraposo avatar pettiboy 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

Watchers

 avatar  avatar

react-ui-scrollspy's Issues

Passing active class to a state hook

I have a menu styled with react semantic ui. Highlighting the active item comes from a state hook that holds the according id.

Instead of using css to highlight the active item

.active-scroll-spy {
  background-color: yellowgreen;
  border-radius: 15px;
}

I would like to be able to get the id from the activeClass and store it in the useState() hook and access it from there to update the menu. I can see that react-ui-scrollspy works as expected from the updated url path. Is it possible to have access to the active class id to manipulate it with JavaScript code?

Option to disable url appending hash

Could you advice how to disable the page url from appending active section as hash?
The reason is because the page has other section (hero) that is not part of the scrollspy <ScrollSpy> .
This cause the page when load to scroll directly to the 1st ScrollSpy element and skipping the rest of the page content.

<hero /> -> height 90vh
<nav />
<ScrollSpy>
<div>
<div>
<ScrollSpy>

Thanks in advance.

React 18 not supported

I am trying to install the plugin to my react project, but it generates some errors because I am using react 18, which is not supported by your plugin.

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@"^18.2.0" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^17.0.2" from [email protected]
npm ERR! node_modules/react-ui-scrollspy
npm ERR!   react-ui-scrollspy@"*" 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 eresolve-report.txt for a full report.

npm ERR! A complete log of this run can be found in:
npm ERR!    .npm/_logs/2023-01-02T23_43_41_009Z-debug-0.log

offsetTop does not seem to be working.

Maybe i am missing out on something, but i cannot get "offsetTop" to work.

I got two columns, left Column consists of Images, right Column consists of teasers. The Teasers Are using the scrollspy functionality.

Desired: The images inside of the left column should change on update and show the image of the active teaser.

So far so good everything works, but if i do want a small offset for the teasers. Nothing changes when i use "offsetTop={500}".
However, a negative "offsetBottom" works, but this is not what i need.

Can someone help me out? Thanks a lot.

Active class to the last element

If the last element has a small height, it isn't selected at the bottom.

Expected result: if container was scrolled to the bottom, the last element has "active" class.

image

Active class not working when section content is dynamic

Active class not working when section content is dynamic

<ScrollSpy offsetBottom={400} scrollThrottle={100} parentScrollContainerRef={this.props.scrollContainer}>
        <section id="system-status">
          {mainStore.proViewShow("system-status") && <div>
              <h2>System Status</h2>
              <Alerts/>
          </div>}
        </section>
</ScrollSpy>

Math for returning to higher offset items appears off

Your own demo does this as well, though less reliably than my own work with more items and a larger offset. Observe this recording:

react-ui-scrollspy-bug

You can see the issue happens twice; once when I click "Section 2" then again when I click "Section 1". Also note as I click "Section 3" afterward, it momentarily jumps to highlight "Section 1" before sliding down through the other items.

It appears as though the window needs to scroll up an additional pixel or three to trigger activation of the correct menu item. It only occurs when scrolling up; I have never seen the issue when clicking an item that scrolls down.

Add active class name doesn't work if component containing data-to-scrollspy-id is in a nested component

@pettiboy Such a life saver react component! Thank you so much.

I debugged with the onUpdateCallback and it is returning the matching id as the link <a data-to-scrollspy-id>
<ScrollSpy scrollThrottle={100} onUpdateCallback={(id: string) => console.log(id)}>

However, the link didn't get class name active-scroll-spy added.
I had similar setup as your demo-app except my <nav> is nested inside another component <hero>

<hero>
  <nav> -> would not work
    <a class="other-classname" data-to-scrollspy-id="section-1">Section 1</a>
    <a class="other-classname" data-to-scrollspy-id="section-2">Section 2</a>
  </nav>
</hero>
<ScrollSpy>
    <div id="section-1">Section 1</div>
    <div id="section-12">Section 2</div>
</ScrollSpy>

How could i make this work with nested component?
Thanks in advance. Appreciate your help.

Active class is not set when scrolling through the content

I have a problem when scrolling through the content - the next navigation items are not set to active. I think it happens because of the modal height. What am I doing wrong here?

      <Modal centered size="lg" show={schedulerSettingsModalIsOpen} onHide={() => setSchedulerSettingsModalIsOpen(false)} >
        <Modal.Header closeButton>
          <Modal.Title>Scheduler Settings</Modal.Title>
        </Modal.Header>
        <Modal.Body className="show-grid">
                <Row>
                  <Col sm={3}>
                    <Nav variant="pills" className="flex-column">
                      <a onClick={(e) => onPress(e)} href="#first">
                        <div data-to-scrollspy-id="first" className={"ss-item"}>
                          first
                        </div>
                      </a>
                      <a onClick={(e) => onPress(e)} href="#second">
                        <div data-to-scrollspy-id="second" className={"ss-item"}>
                          second
                        </div>
                      </a>
                      <a onClick={(e) => onPress(e)} href="#third">
                        <div data-to-scrollspy-id="third" className={"ss-item"}>
                          third
                        </div>
                      </a>
                    </Nav>
                  </Col>
                  <Col sm={9} ref={parentScrollContainerRef}>
                    <Form
                      style={{
                        position: "relative",
                        overflowY: "scroll",
                        height: "30vh",
                      }}>
                      <ScrollSpy activeClass={"active-nav-item"} onUpdateCallback={(id) => console.log(id)}>
                        <div id="first" style={{height: "30vh"}}>
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                        </div>
                        <div id="second" style={{height: "50vh"}}>
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                          fdsafdsafdsfdsfdsfdsfdsfsfsdfdsfsadfdsafdsafdasfdsafdsafdsafdsa
                        </div>
                        <div id="third" style={{height: "50vh"}}>
                          1112222222222222222222
                        </div>
                      </ScrollSpy>
                    </Form>
                  </Col>
                </Row>
        </Modal.Body>
        <Modal.Footer>
          <Button variant="secondary" onClick={() => setSchedulerSettingsModalIsOpen(!schedulerSettingsModalIsOpen)}>
            Close
          </Button>
          <Button type="submit" variant="primary" onClick={(e) => handleSubmitClick(e)} disabled={hasErrors}>
            Save Changes
          </Button>
        </Modal.Footer>
      </Modal>

image

Error trying to build

I get this error after running npm install and npm run build

[email protected] build
rollup -c

Error loading `tslib` helper library.
[!] Error: Package subpath './package.json' is not defined by "exports" in D:\Side Projects\react-ui-scrollspy\node_modules\tslib\package.json
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './package.json' is not defined by "exports" in D:\Side Projects\react-ui-scrollspy\node_modules\tslib\package.json
    at new NodeError (node:internal/errors:393:5)
    at exportsNotFound (node:internal/modules/esm/resolve:295:10)
    at packageExportsResolve (node:internal/modules/esm/resolve:631:9)
    at resolveExports (node:internal/modules/cjs/loader:538:36)
    at Function.Module._findPath (node:internal/modules/cjs/loader:607:31)
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:1025:27)
    at Function.Module._load (node:internal/modules/cjs/loader:885:27)
    at Module.require (node:internal/modules/cjs/loader:1105:19)
    at require (node:internal/modules/cjs/helpers:103:18)
    at Object.<anonymous> (D:\Side Projects\react-ui-scrollspy\node_modules\rollup-plugin-typescript2\src\tslib.ts:11:23)

Allow activeClass to receive multiple classes

As of today, when passing multiple classes to the prop activeClass (i.e. activeClass="font-bold text-blue-500") an exception is thrown:

Uncaught DOMException: Failed to execute 'add' on 'DOMTokenList': The token provided ('font-bold text-blue-500') contains HTML space characters, which are not valid in tokens.

This is because classList.add does not support passing multiple classes separated by a whitespace. To avoid introducing a breaking change (like changing the type of activeClass to receive an array) the string could be splited by whitespaces classList.add(...activeClass.split(' ')).

PS: Great library!

Nested structure not supported

Nice component, but doesn't seem supporting nested HTML structure, like—

<chapter>
  <header id="section1">Chapter 1</header>
  <main>
    <section>
      <header id="subheaderA">Subheader A</header>
    </section>
    <section>
      <header id="subheaderB">Subheader B</header>
    </section>
  </main>
</chapter>

In this example, if we are on Subheader A, react-ui-scrollspy will still highlight Chapter 1 as active.

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.