React Sticky Box
See it in Action
The sidebar to the left stays in a sticky position.
Go ahead and hit the expand button to see how it behaves once the sidebar becomes greater than the viewport.
What the Code looks like
import React from "react";
import StickyBox from "react-sticky-box";
const Page = () => (
<div className="row">
<StickyBox offsetTop={20} offsetBottom={20}>
<div>Sidebar</div>
</StickyBox>
<div>Content</div>
</div>
);
How to install
yarn add react-sticky-box
npm install react-sticky-box
How it works
React Sticky Box relies on position: sticky
. It’s widely supported these days.
For all browsers without sticky support, it falls back to a position: relative
behaviour. This could be considered “good enough” in a lot of cases. Alternatively you have to provide a custom solution to get sticky behaviour here. Either via polyfills or even targeting IE10+ Browsers via @media queries
like presented here by Olivr3.
position: sticky
isn’t without it’s issues though. If the content is bigger than the viewport, it simply gets cut off and becomes inaccessible. This library solves this issue by allowing the content to scroll along with all the other content until the the corresponding end is visible and continues to be sticky.
You still might encounter browser bugs with position: sticky
if your content lies within certain combinations of z-index
, overflow
and especially transform
.
What kind of scroll containers can be used
Window
<body>
<div style={{display: "flex", alignItems: "flex-start"}}>
<StickyBox>Sidebar</StickyBox>
<div>Main Content</div>
</div>
</body>
Scroll Container as offset parent
<div style={{height: 200, position: "relative", overflow: "auto"}}>
<div style={{position: "absolute", top: 0, left: 0, right: 0, minHeight: "100%"}}>
<div style={{display: "flex", alignItems: "flex-start"}}>
<StickyBox>Sidebar</StickyBox>
<div>Main Content</div>
</div>
</div>
</div>
Scroll Container as non-offset parent
<div style={{height: 200, overflow: "auto"}}>
<div style={{display: "flex", alignItems: "flex-start"}}>
<StickyBox>Sidebar</StickyBox>
<div>Main Content</div>
</div>
</div>
Troubleshooting
The StickyBox is not sticky!
Make sure that the <StickyBox>
is only as high as its content, and not as high as the parent node. To quickly check this you can do:
<StickyBox style={{border: "3px solid green"}}>content</StickyBox>
Good
<div style={{display: "flex", alignItems: "flex-start"}}>
<StickyBox style={{border: "3px solid green"}}>Sidebar</StickyBox>
<div style={{height: 150, border: "3px solid blue"}}>Main Content</div>
</div>
Bad
This time without alignItems: "flex-start"
<div style={{display: "flex"}}>
<StickyBox style={{border: "3px solid green"}}>Sidebar</StickyBox>
<div style={{height: 150, border: "3px solid blue"}}>Main Content</div>
</div>
Is this production-ready?
This library is heavily used within Codecks, so expect it to be fairly stable.