React Sticky Component
`react-sticky` is a JavaScript library designed to implement sticky UI elements within React applications. It provides a robust, programmatically controlled solution for scenarios where native CSS `position: sticky` falls short, particularly regarding older browser support (like IE11) or specific layout complexities (e.g., table elements). The current stable version, 6.0.3, was a significant redesign, transitioning to a higher-order component (HOC) pattern combined with a render prop API, which offers developers fine-grained control over the sticky behavior. It requires `react` and `react-dom` versions 15.3 or higher. While no explicit release cadence is stated, major version updates have historically aligned with significant React ecosystem changes. Its key differentiator is providing a flexible, JavaScript-driven approach when CSS alternatives are not viable, allowing custom logic and rendering based on the element's sticky state. This approach provides a fallback for environments where modern CSS features are not fully supported or when more dynamic, JavaScript-controlled sticky behavior is required beyond what pure CSS offers.
Common errors
-
Error: Objects are not valid as a React child (found: object with keys {$$typeof, type, key, ref, props, _owner, _store}). If you meant to render a collection of children, use an array instead.cause The `Sticky` component received a plain React element as a child instead of a render prop function.fixWrap your content inside `Sticky` with a function, e.g., `<Sticky>{({ style }) => <div style={style}>Your Content</div>}</Sticky>`. -
The sticky element is not sticking, even when scrolling.
cause This usually happens if the `Sticky` component is not nested within a `StickyContainer`, or if the `StickyContainer` itself does not have enough scrollable content to trigger the sticky behavior, or if conflicting CSS styles are applied.fixEnsure `<Sticky>` is a descendant of `<StickyContainer>`. Verify there's sufficient scrollable content to make the element sticky. Inspect parent/sibling CSS for properties like `overflow: hidden` or `position: absolute` that might disrupt positioning context. -
TypeError: Cannot read properties of undefined (reading 'style')
cause The render prop function for `Sticky` is not correctly destructuring the properties, leading to `style` being undefined when accessed.fixEnsure the render prop function explicitly destructures `style` from its argument, e.g., `({ style, isSticky }) => ...`.
Warnings
- breaking `react-sticky` version 6.x dropped support for React versions older than 15.3. If you are using an earlier React version, you must use the 5.x series.
- gotcha The `Sticky` component requires a function as its direct child (a render prop). Providing a plain React element will result in an error or incorrect behavior.
- gotcha CSS `position: sticky` is often a simpler and more performant solution if browser support (especially IE11) and specific layout requirements allow it. Evaluate CSS alternatives before opting for a JavaScript solution.
- gotcha Certain CSS styles (e.g., `overflow: hidden`, `position: absolute`, `transform`) on parent elements or between `StickyContainer` and `Sticky` can interfere with the positioning logic and prevent sticky behavior.
Install
-
npm install react-sticky -
yarn add react-sticky -
pnpm add react-sticky
Imports
- StickyContainer
const { StickyContainer } = require('react-sticky')import { StickyContainer } from 'react-sticky' - Sticky
const { Sticky } = require('react-sticky')import { Sticky } from 'react-sticky' - { style, isSticky } (render prop arguments)
<Sticky><div>...</div></Sticky>
<Sticky>{({ style, isSticky }) => <div style={style}>...</div>}</Sticky>
Quickstart
import React from 'react';
import { StickyContainer, Sticky } from 'react-sticky';
class App extends React.Component {
render() {
// Mimic some scrollable content to demonstrate stickiness
const content = Array.from({ length: 50 }, (_, i) => (
<p key={i} style={{ padding: '10px 0', borderBottom: '1px solid #eee' }}>
Scrollable content item {i + 1}
</p>
));
return (
<div style={{ height: '1500px' }}> {/* Ensure enough height for scrolling */}
<StickyContainer>
<div style={{ padding: '20px', background: '#f0f0f0' }}>
<h2>Above Sticky Section</h2>
<p>This content is before the sticky element.</p>
</div>
<Sticky>
{({ style, isSticky }) => (
<header
style={{
...style,
background: isSticky ? 'lightblue' : 'lightgray',
padding: '10px',
textAlign: 'center',
fontWeight: 'bold',
boxShadow: isSticky ? '0 2px 5px rgba(0,0,0,0.2)' : 'none'
}}
>
{isSticky ? 'I am Sticky!' : 'Scroll down to make me sticky!'}
</header>
)}
</Sticky>
<div style={{ padding: '20px' }}>
<h3>Below Sticky Section</h3>
<p>This content is below the sticky element and will scroll underneath it.</p>
{content}
</div>
</StickyContainer>
</div>
);
}
}
export default App;