Skip to content

Instantly share code, notes, and snippets.

@brthornbury
Created February 3, 2017 05:49
Show Gist options
  • Save brthornbury/27531e4616b68131e512fc622a61baba to your computer and use it in GitHub Desktop.
Save brthornbury/27531e4616b68131e512fc622a61baba to your computer and use it in GitHub Desktop.
Simple ReactJS component to support a navbar becoming visible after the user scrolls down the page.

Ensure you have raf installed: npm install --save raf

This is the code for the component.

import raf from 'raf';

export default class ScrollInNav extends Component {
  static propTypes = {
    scrollInHeight: React.PropTypes.number
  };

  static defaultProps = {
    scrollInHeight: 50
  };

  fixedStyle = {
      position: 'fixed',
      WebkitTransition: 'all .2s ease-in-out',
      MozTransition: 'all .2s ease-in-out',
      OTransition: 'all .2s ease-in-out',
      transition: 'all .2s ease-in-out',
      top: 0,
      left: 0,
      right: 0,
      zIndex: 1
  };

  hiddenStyle = {
      WebkitTransform: 'translateY(-100%)',
      MsTransform: 'translateY(-100%)',
      transform: 'translateY(-100%)'
  };

  scrolledInStyle = {
      WebkitTransform: 'translateY(0)',
      MsTransform: 'translateY(0)',
      transform: 'translateY(0)'
  };

  constructor(props) {
    super(props);

    this.state = {
      hidden: true
    };

    this.handlingScrollUpdate = false;
  }

  getScrollY = () => {
    if (window.pageYOffset !== undefined) {
      return window.pageYOffset
    } else if (window.scrollTop !== undefined) {
      return window.scrollTop
    } else {
      return (document.documentElement || document.body.parentNode || document.body).scrollTop
    }
  }

  handleScroll = () => {
     if (!this.handlingScrollUpdate) {
      this.handlingScrollUpdate = true;
      raf(this.update);
    }
  }

  update = () => {
    let currentScrollY = this.getScrollY();
    console.log(currentScrollY);
    console.log(this.props.scrollInHeight);

    this.setState({
      hidden: currentScrollY < this.props.scrollInHeight
    });

    this.handlingScrollUpdate = false;
  }

  componentDidMount() {
    window.addEventListener('scroll', this.handleScroll);
  }

  componentWillUnmount() {
    window.removeEventListener('scroll', this.handleScroll);
  }

  render() {
    let renderStyle = this.fixedStyle;
    renderStyle = this.state.hidden ?
        {...renderStyle, ...this.hiddenStyle} :
        {...renderStyle, ...this.scrolledInStyle};

    return (
        <div className="scroll-in-nav" ref="scrollnav" style={renderStyle}>
          {this.props.children}
        </div>
    );
  }
}

A simple example using a default react-bootstrap navbar:

class MyNavBar extends Component {
    render() {
      return (
        <ScrollInNav scrollInHeight={50}>
          <Navbar inverse collapseOnSelect>
            <Navbar.Header>
              <Navbar.Brand>
                <a href="#">React-Bootstrap</a>
              </Navbar.Brand>
              <Navbar.Toggle />
            </Navbar.Header>
            <Navbar.Collapse>
              <Nav>
                <NavItem eventKey={1} href="#">Link</NavItem>
                <NavItem eventKey={2} href="#">Link</NavItem>
                <NavDropdown eventKey={3} title="Dropdown" id="basic-nav-dropdown">
                  <MenuItem eventKey={3.1}>Action</MenuItem>
                  <MenuItem eventKey={3.2}>Another action</MenuItem>
                  <MenuItem eventKey={3.3}>Something else here</MenuItem>
                  <MenuItem divider/>
                  <MenuItem eventKey={3.3}>Separated link</MenuItem>
                </NavDropdown>
              </Nav>
              <Nav pullRight>
                <NavItem eventKey={1} href="#">Link Right</NavItem>
                <NavItem eventKey={2} href="#">Link Right</NavItem>
              </Nav>
            </Navbar.Collapse>
          </Navbar>
        </ScrollInNav>
      );
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment