Last active
November 3, 2024 22:05
-
-
Save tammyhart/eabe13624914cc8bbf0331eda51d2234 to your computer and use it in GitHub Desktop.
useStickyRef.js - Add class when stuck
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* essential styles for hook to work */ | |
header { | |
/* | |
this is set in the JS so the the primary behavior isn't dependant on the stylesheet | |
position: sticky; | |
top: -1px; | |
*/ | |
} | |
/* styles for when header is stuck */ | |
header.stuck { | |
background: rgba(0, 0, 0, 0.5); | |
} | |
/* styles for presentation purposes */ | |
body { | |
background: linear-gradient( | |
to bottom, | |
rgba(0, 0, 0, 0) 0%, | |
rgba(0, 0, 0, 0.5) 100% | |
), | |
#2A3B46; | |
margin: 0; | |
font-family: sans-serif; | |
color: white; | |
} | |
div { | |
height: 300vh; | |
} | |
header { | |
padding: 1rem; | |
transition: .3s ease-out; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react" | |
import ReactDOM from "react-dom" | |
import useStickyRef from "./useStickyRef" | |
import "./App.css" | |
// use the hook on the header element | |
const App = () => { | |
const stickyRef = useStickyRef() | |
return ( | |
<div> | |
<br /><br /><br /><br /> | |
<header ref={stickyRef}> | |
Scroll to see me change when I'm stuck | |
</header> | |
</div> | |
) | |
} | |
// render the app on the #root element in the HTML | |
ReactDOM.render( | |
<React.StrictMode> | |
<App /> | |
</React.StrictMode>, | |
document.getElementById('root') | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useEffect, useRef } from "react" | |
const useStickyRef = () => { | |
const ref = useRef(null) | |
useEffect(() => { | |
// https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API | |
const observer = new IntersectionObserver( | |
([entry]) => { | |
if (ref.current) { | |
// toggle the class when the entry intersects in and out | |
ref.current.classList.toggle("stuck", entry.intersectionRatio < 1) | |
} | |
}, | |
// execute callback when target is fully visible | |
{ threshold: 1.0 } | |
); | |
if (ref.current) { | |
// set this here so we don't have to depend on the stylesheet for the essentials | |
ref.current.style.position = "sticky" | |
// required for `position: sticky` to work | |
// less than 0 required for `intersectionRatio < 1` to work | |
ref.current.style.top = "-1px" | |
// observe the element | |
observer.observe(ref.current) | |
} | |
// stop observing on unmount | |
return () => { | |
if (ref.current) { | |
observer.unobserve(ref.current) | |
} | |
} | |
}, [ref]) | |
return ref | |
} | |
export default useStickyRef |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment