NPM Version NPM Downloads GitHub Stars Build Status License TypeScript SSR/SSG Compatible
A lightweight, flexible React sticky container and item component library. Easily create sticky headers, sections, and advanced sticky layouts with support for multiple modes and edge cases.
- π¦ Simple API:
<StickyContainer>and<StickyItem> - π§© Supports
replace,stack, andnonesticky modes - π·οΈ Customizable offset, z-index (baseZIndex), and sticky logic
- π₯οΈ Flexible reference containers (window, DOM elements, refs)
- π Supports SSR/SSG (Next.js, Gatsby, Astro, etc.)
- π§ͺ Handles edge cases: empty sections, dynamic heights, zero-height headers, long headers, etc.
- β‘οΈ Written in TypeScript, fully typed
- π§ͺ Includes demo pages for real-world scenarios
npm install react-sticky-kit # or yarn add react-sticky-kit # or pnpm add react-sticky-kit
import { StickyContainer, StickyItem } from 'react-sticky-kit'; // !! Import styles for sticky components import 'react-sticky-kit/dist/style.css'; // or `import 'react-sticky-kit/style';` for more clean style path(require modern bundler tools) export default function Example() { return ( <StickyContainer offsetTop={48} defaultMode="stack" baseZIndex={300}> <StickyItem> <div>Sticky Header</div> </StickyItem> <div>Content...</div> <StickyItem mode="replace"> <div>Another Sticky Header (replace mode)</div> </StickyItem> <div>More Content...</div> </StickyContainer> ); }
| Prop | Type | Default | Description |
|---|---|---|---|
offsetTop |
number |
0 |
Offset from the top of the viewport |
defaultMode |
'replace' | 'stack' | 'none' |
'replace' |
Default sticky mode for all items |
baseZIndex |
number |
200 |
Base z-index for sticky items. Should be greater than the number of sticky items. |
In replace mode, z-index = baseZIndex - index; in stack mode, z-index = baseZIndex + index. |
|||
onStickyItemsHeightChange |
(height: number) => void |
Callback when total sticky height changes | |
constraint |
'none' |
Define the constraint for sticky behavior. 'none' = no constraints (CSS-like behavior) |
| Prop | Type | Default | Description |
|---|---|---|---|
mode |
'replace' | 'stack' | 'none' |
Sticky mode for this item (overrides StickyContainer) |
- replace: Only one sticky item is visible at a time, replacing the previous.
- stack: Sticky items stack on top of each other.
- none: Sticky is disabled for this item.
The constraint prop allows you to control when sticky items should stop being sticky:
import React from 'react'; import { StickyContainer, StickyItem } from 'react-sticky-kit'; function Example() { return ( <div> {/* 1. Default: Container-based constraint */} <StickyContainer> <StickyItem><div>Sticky stops when container leaves viewport</div></StickyItem> <div>Content...</div> </StickyContainer> {/* 2. No constraints (like CSS position:sticky) */} <StickyContainer constraint="none"> <StickyItem><div>Always sticky like CSS position:sticky</div></StickyItem> <div>Content...</div> </StickyContainer> </div> ); } <div>Content...</div> </StickyContainer> </div> ); }
When you set constraint="none", the sticky items will always stick when they reach the top of the viewport, regardless of their parent container's visibility. This exactly matches the behavior of native CSS position: sticky.
In contrast, the default behavior (without specifying a constraint) only makes items sticky when their parent container is visible in the viewport.
Run the demo locally:
pnpm install pnpm dev
Open http://localhost:5173 and switch between demo pages to explore all features and edge cases:
- iOS Contact a dead simple iOS contact clone
- Mixed mode mix replace/stack/none mode
- Nested nest sticky containers
- Dynamic sticky items dynamic sticky items(add/remove)
- Dynamic offsetTop dynamic offsetTop that adapts to header height changes
- Constraint Demo demo showing different constraint options
React Sticky Kit supports Server-Side Rendering (SSR) and Static Site Generation (SSG), working seamlessly with frameworks like Next.js, Gatsby, Astro, and more.
// pages/index.tsx import { StickyContainer, StickyItem } from 'react-sticky-kit' import 'react-sticky-kit/dist/style.css' export default function Home() { return ( <StickyContainer> <StickyItem> <header>Sticky Header</header> </StickyItem> <main>Content...</main> </StickyContainer> ) }
--- // src/pages/index.astro import { StickyContainer, StickyItem } from 'react-sticky-kit' import 'react-sticky-kit/dist/style.css' --- <html> <head>...</head> <body> <StickyContainer client:load> <StickyItem> <header>Sticky Header</header> </StickyItem> <div>Content...</div> </StickyContainer> </body> </html>
pnpm pub
MIT