Skip to content

Commit d0e9ab1

Browse files
committed
✨ NEW: customizable data attributes and active class
1 parent b0ede23 commit d0e9ab1

File tree

11 files changed

+231
-79
lines changed

11 files changed

+231
-79
lines changed

README.md

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ OR
2424
yarn add react-ui-scrollspy
2525
```
2626

27-
## ⚙️ Getting started
27+
## ⚙️ Usage
2828

2929
1. In your navigation component
3030

@@ -68,15 +68,44 @@ import ScrollSpy from "react-ui-scrollspy";
6868

6969
## 💡 Props
7070

71-
| Attributes | Type | Description | Default | Required |
72-
| :------------------------- | :----------------------------------------- | :--------------------------------------------------------------------------------------------------------------------- | :------ | :------- |
73-
| `children` | `ReactNode` | Each direct child `Element` should contain an `id` | - | yes |
74-
| `scrollThrottle` | `number` | in `milliseconds` to throttle the `onscroll` event. Lower the number, better the response, higher the performance cost | 300 | no |
75-
| `navContainerRef` | `MutableRefObject<HTMLDivElement \| null>` | `ref` to your navigation container containing items with `data-to-scrollspy-id` attributes | - | no |
76-
| `onUpdateCallback` | `(id: string) => void` | Executes this function whenever you scroll to an `Element`, callback returns the `id` of that `Element` as well | - | no |
77-
| `parentScrollContainerRef` | `MutableRefObject<HTMLDivElement \| null>` | If you want to spy only on a particular scrollable `container (Element)` then pass a ref of the same to this prop | - | no |
78-
| `offsetTop` | `number` | spy will be fired when it has been scrolled `offsetTop` beyond `50%` to the top of the containing element | 0 | no |
79-
| `offsetBottom` | `number` | spy will be fired when it has been scrolled `offsetBottom` beyond `50%` to the bottom of the containing element | 0 | no |
71+
### Children
72+
73+
| Attributes | Type | Description | Default | Required |
74+
| :--------- | :---------- | :------------------------------------------------- | :------ | :------- |
75+
| `children` | `ReactNode` | Each direct child `Element` should contain an `id` | - | yes |
76+
77+
### Refs
78+
79+
| Attributes | Type | Description | Default | Required |
80+
| :------------------------- | :------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------- | :------ | :------- |
81+
| `navContainerRef` | MutableRefObject<br><HTMLDivElement \| null><br/> | `ref` to your navigation container containing items with `data-to-scrollspy-id` attributes | - | no |
82+
| `parentScrollContainerRef` | MutableRefObject<br><HTMLDivElement \| null><br/> | If you want to spy only on a particular scrollable `container (Element)` then pass a ref of the same to this prop | - | no |
83+
84+
### Throlle
85+
86+
| Attributes | Type | Description | Default | Required |
87+
| :--------------- | :------- | :--------------------------------------------------------------------------------------------------------------------- | :------ | :------- |
88+
| `scrollThrottle` | `number` | In `milliseconds` to throttle the `onscroll` event. Lower the number, better the response, higher the performance cost | `300` | no |
89+
90+
### Callback
91+
92+
| Attributes | Type | Description | Default | Required |
93+
| :----------------- | :--------------------- | :-------------------------------------------------------------------------------------------------------------- | :------ | :------- |
94+
| `onUpdateCallback` | `(id: string) => void` | Executes this function whenever you scroll to an `Element`, callback returns the `id` of that `Element` as well | - | no |
95+
96+
### Offsets
97+
98+
| Attributes | Type | Description | Default | Required |
99+
| :------------- | :------- | :-------------------------------------------------------------------------------------------------------------- | :------ | :------- |
100+
| `offsetTop` | `number` | Spy will be fired when it has been scrolled `offsetTop` beyond `50%` to the top of the containing element | `0` | no |
101+
| `offsetBottom` | `number` | Spy will be fired when it has been scrolled `offsetBottom` beyond `50%` to the bottom of the containing element | `0` | no |
102+
103+
### Customize Attributes
104+
105+
| Attributes | Type | Description | Default | Required |
106+
| :----------------- | :------- | :----------------------------------------------------------- | :-------------------- | :------- |
107+
| `useDataAttribute` | `string` | To customize the string after `data-` | `"to-scrollspy-id"` | no |
108+
| `activeClass` | `string` | To customize the `class` added when the `Element` is in view | `"active-scroll-spy"` | no |
80109

81110
## 📝 Authors
82111

demo-app/src/App.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import Center from "./components/Center/Center";
22
import Navigation from "./components/Navigation/Navigation";
3+
// eslint-disable-next-line
34
import ScrollSpy from "react-ui-scrollspy";
5+
// eslint-disable-next-line
46
import ScrollSpyDev from "./components/src";
57

68
function App() {
79
return (
810
<div>
911
<Navigation />
1012

11-
<ScrollSpyDev scrollThrottle={100}>
13+
<ScrollSpy scrollThrottle={100}>
1214
<Center id="orange" backgroundColor={"orange"}>
1315
<h1>Orange</h1>
1416
</Center>
@@ -21,7 +23,7 @@ function App() {
2123
<Center id="green" backgroundColor={"green"}>
2224
<h1>Green</h1>
2325
</Center>
24-
</ScrollSpyDev>
26+
</ScrollSpy>
2527
</div>
2628
);
2729
}

demo-app/src/components/src/ScrollSpy/ScrollSpy.tsx

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,46 @@ import { throttle } from "../utils/throttle";
1111

1212
interface ScrollSpyProps {
1313
children: ReactNode;
14+
15+
// refs
1416
navContainerRef?: MutableRefObject<HTMLDivElement | null>;
1517
parentScrollContainerRef?: MutableRefObject<HTMLDivElement | null>;
18+
19+
// throttle
1620
scrollThrottle?: number;
21+
22+
// callback
1723
onUpdateCallback?: (id: string) => void;
24+
25+
// offsets
1826
offsetTop?: number;
1927
offsetBottom?: number;
28+
29+
// customize attributes
30+
useDataAttribute?: string;
31+
activeClass?: string;
2032
}
2133

2234
const ScrollSpy = ({
2335
children,
36+
37+
// refs
2438
navContainerRef,
2539
parentScrollContainerRef,
26-
onUpdateCallback,
40+
41+
// throttle
2742
scrollThrottle = 300,
43+
44+
// callback
45+
onUpdateCallback,
46+
47+
// offsets
2848
offsetTop = 0,
2949
offsetBottom = 0,
50+
51+
// customize attributes
52+
useDataAttribute = "to-scrollspy-id",
53+
activeClass = "active-scroll-spy",
3054
}: ScrollSpyProps) => {
3155
const scrollContainerRef = useRef<HTMLDivElement | null>(null);
3256
const [navContainerItems, setNavContainerItems] = useState<NodeListOf<Element> | undefined>(); // prettier-ignore
@@ -37,13 +61,15 @@ const ScrollSpy = ({
3761

3862
// To get the nav container items depending on whether the parent ref for the nav container is passed or not
3963
useEffect(() => {
40-
if (navContainerRef) {
41-
setNavContainerItems(
42-
navContainerRef.current?.querySelectorAll("[data-to-scrollspy-id]")
43-
);
44-
} else {
45-
setNavContainerItems(document.querySelectorAll("[data-to-scrollspy-id]"));
46-
}
64+
navContainerRef
65+
? setNavContainerItems(
66+
navContainerRef.current?.querySelectorAll(
67+
`[data-${useDataAttribute}]`
68+
)
69+
)
70+
: setNavContainerItems(
71+
document.querySelectorAll(`[data-${useDataAttribute}]`)
72+
);
4773

4874
// eslint-disable-next-line react-hooks/exhaustive-deps
4975
}, [navContainerRef]);
@@ -85,20 +111,20 @@ const ScrollSpy = ({
85111

86112
// now loop over each element in the nav Container
87113
navContainerItems.forEach((el) => {
88-
const attrId = el.getAttribute("data-to-scrollspy-id");
114+
const attrId = el.getAttribute(`data-${useDataAttribute}`);
89115

90116
// if the element contains 'active' the class remove it
91-
if (el.classList.contains("active-scroll-spy")) {
92-
el.classList.remove("active-scroll-spy");
117+
if (el.classList.contains(activeClass)) {
118+
el.classList.remove(activeClass);
93119
}
94120

95121
// check if its ID matches the ID we got from the viewport
96122
// also make sure it does not already contain the 'active' class
97123
if (
98124
attrId === changeHighlightedItemId &&
99-
!el.classList.contains("active-scroll-spy")
125+
!el.classList.contains(activeClass)
100126
) {
101-
el.classList.add("active-scroll-spy");
127+
el.classList.add(activeClass);
102128

103129
if (onUpdateCallback) {
104130
onUpdateCallback(changeHighlightedItemId);

demo-app/src/components/src/utils/isVisible.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { MutableRefObject } from "react";
2-
31
// to check if the element is in viewport
42
export const isVisible = (
53
el: HTMLElement,

dev.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ git commit -m "‼️ BREAKING: "
2626
- [x] callbacks
2727
- [x] offset props
2828
- [x] relative positioning handled
29-
- [ ] customise data attributes
30-
- [ ] description, keywords
29+
- [x] customise data attributes
30+
- [x] description, keywords
3131
- [ ] deploy test website on github pages
3232
- [x] update docs
3333
- [ ] deploy as version 2

dist/ScrollSpy/ScrollSpy.d.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ import { MutableRefObject, ReactNode } from "react";
22
interface ScrollSpyProps {
33
children: ReactNode;
44
navContainerRef?: MutableRefObject<HTMLDivElement | null>;
5+
parentScrollContainerRef?: MutableRefObject<HTMLDivElement | null>;
56
scrollThrottle?: number;
7+
onUpdateCallback?: (id: string) => void;
8+
offsetTop?: number;
9+
offsetBottom?: number;
10+
useDataAttribute?: string;
11+
activeClass?: string;
612
}
7-
declare const ScrollSpy: ({ children, navContainerRef, scrollThrottle, }: ScrollSpyProps) => JSX.Element;
13+
declare const ScrollSpy: ({ children, navContainerRef, parentScrollContainerRef, scrollThrottle, onUpdateCallback, offsetTop, offsetBottom, useDataAttribute, activeClass, }: ScrollSpyProps) => JSX.Element;
814
export default ScrollSpy;

dist/index.js

Lines changed: 50 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)