Skip to content

Instantly share code, notes, and snippets.

@dreamyguy
Last active February 21, 2020 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dreamyguy/3f60748d8993246450cef0e223e23d33 to your computer and use it in GitHub Desktop.
Save dreamyguy/3f60748d8993246450cef0e223e23d33 to your computer and use it in GitHub Desktop.
A React component with `position: sticky` support and fallback fot browsers that don't support it

React Position Sticky

I needed a component that would provide the following:

  • Native position: sticky, if supported
  • position: sticky fallback for older browsers, like IE11
  • Support for children to be passed down as props

So I came up with the following:

import React from 'react';
import PropTypes from 'prop-types';
import { StickyContainer, Sticky } from 'react-sticky';
import positionsticky from 'modernizr-esm/feature/css/positionsticky';

const stylesStickyWrapper = {
  position: 'relative',
  height: '100%',
};

const stylesSticky = {
  position: 'sticky',
  top: '0',
  height: 'auto',
};

const PositionSticky = props => {
  const { children } = props;

  return (
    <>
      {positionsticky ? (
        <div style={stylesStickyWrapper}>
          <div style={stylesSticky}>
            {children}
          </div>
        </div>
      ) : (
        <StickyContainer style={{ position: 'relative', height: '100%' }}>
          <Sticky>
            {({ style }) => (
              <div style={style}>
                {children}
              </div>
            )}
          </Sticky>
        </StickyContainer>
      )}
    </>
  );
};

PositionSticky.propTypes = {
  children: PropTypes.node.isRequired,
};

export default PositionSticky;

Usage

Simple:

<PositionSticky>
  <p>Your content here</p>
</PositionSticky>

Real world scenario:

<div className="row">
  <div className="col-12 col-md-6">
    <PositionSticky>
      <p>Blah.</p>
    </PositionSticky>
  </div>
  <div className="col-12 col-md-6">
    <PositionSticky>
      <p>Blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah.</p>
    </PositionSticky>
  </div>
</div>

In the example above, which was the one I ended up with, the length of the content for each colum can vary, causing only the one with less content to trigger its "stickyness", because its parent's height is set by the taller column.

Gotcha!

The Gotchas of `position: sticky has all the gotchas one should take into consideration.

TLDR;

  • The immediate parent should have a taller height, or the effect won't be observed.
  • If you intend to get position sticky relative to the viewport, make shure that all ancestors relative to the element getting position: sticky don't have overflow set.
<div class="overflow-auto"> <!-- overflow: auto -->
  <div>
    <div>
      <div>
        <div class="sticky-parent"> <!-- position: relative; height: 100% -->
          <div class="sticky"> <!-- position: sticky, top: 0 -->
            <p><em>This container won't get sticky at all because it has an ancestor with overflow property set to 'auto'.</em></p>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

Related links:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment