React Sticky Element
react-sticky-el is a React component library designed to make elements stick to the viewport or a specified scrollable container as the user scrolls. It provides a straightforward `<Sticky />` component that can make any child element fixed to the top or bottom. The current stable version is 2.1.1, released in late 2021, and the project is generally considered to be in maintenance mode with infrequent updates. Key differentiators include its relative simplicity, support for custom scroll elements via the `scrollElement` prop, the ability to define a `boundaryElement` to limit stickiness, and flexible configuration for position re-checks. It ships with TypeScript type definitions, providing a typed developer experience.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'default')
cause Attempting to import the `Sticky` component in a CommonJS environment using `require('react-sticky-el')` without explicitly accessing the default export.fixChange your import statement from `const Sticky = require('react-sticky-el');` to `const Sticky = require('react-sticky-el').default;`. -
Warning: Prop `className` did not match. Server: "sticky" Client: ""
cause This hydration mismatch warning can occur in Server-Side Rendering (SSR) environments when the `stickyClassName` or `stickyStyle` are applied dynamically on the client, differing from the server-rendered output.fixFor SSR applications, ensure that the initial state of the `Sticky` component's class or style is consistent between server and client, or conditionally render the sticky behavior only on the client side after initial hydration.
Warnings
- gotcha The component's internal height calculation does not account for `margin` styles applied directly to the sticky element's child, which can lead to unexpected positioning or overlap when the element becomes sticky.
- gotcha Avoid overriding `left`, `top`, and `width` properties within the `stickyStyle` prop. These CSS properties are dynamically managed by `react-sticky-el` for correct positioning and width adjustment.
- gotcha If your DOM structure is dynamic (e.g., elements are added or removed above the sticky component), `react-sticky-el` may not automatically re-evaluate its position, leading to incorrect stickiness. Scroll events alone might not be sufficient.
- gotcha While the peer dependencies specify `React >=16.3.0`, the project's maintenance status and older internal implementations (e.g., reliance on certain lifecycle methods) might lead to compatibility issues or warnings with React 18+.
Install
-
npm install react-sticky-el -
yarn add react-sticky-el -
pnpm add react-sticky-el
Imports
- Sticky
import { Sticky } from 'react-sticky-el';import Sticky from 'react-sticky-el';
- StickyProps
import type { StickyProps } from 'react-sticky-el'; - Sticky (CommonJS)
const Sticky = require('react-sticky-el');const Sticky = require('react-sticky-el').default;
Quickstart
import React, { Component } from 'react';
import Sticky from 'react-sticky-el';
interface AppProps {}
interface AppState {}
class App extends Component<AppProps, AppState> {
render() {
return (
<div style={{ height: '200vh', paddingBottom: '50px' }}>
<p>Scroll down to see the header stick. This is some introductory content to create scroll space.</p>
<div style={{ height: '500px', background: '#f0f0f0', marginBottom: '20px', padding: '20px' }}>
Content before the sticky element. This area ensures that there's enough room to scroll before the header needs to become sticky.
</div>
<Sticky>
<header style={{ background: '#333', color: 'white', padding: '15px 20px', textAlign: 'center', boxShadow: '0 2px 5px rgba(0,0,0,0.2)' }}>
<h2>This header will stick to the top!</h2>
</header>
</Sticky>
<div style={{ height: '800px', background: '#e0e0e0', marginTop: '20px', padding: '20px' }}>
Content after the sticky element. Continue scrolling to observe the sticky behavior in action.
The `react-sticky-el` component gracefully handles making the header fixed to the viewport
while reserving its original space in the document flow, preventing layout shifts. You can try changing the boundary element or scroll element properties for more complex scenarios.
</div>
</div>
);
}
}
export default App;