Search code examples
javascriptreactjstypescriptstyled-components

Change styled-component styling based on window.pageYOffset


So I have component that I would like to change the styling of based on the window.pageYOffset value. When the user scrolls down X value, I would like to change the background color, although this should not be limited to just the background color as I may also want to change other properties, such as the font-size, color, padding and so forth.

Here's what I currently have.

const AppHeader: React.FC = () => {
  const [scrollY, setScrollY] = React.useState('')

  function handleScroll() {
    if (window.pageYOffset > 1) {
      // Be able to change styling properties based on true / false.
    }
  }

  React.useEffect(() => {
    window.addEventListener('scroll', handleScroll)
    return () => {
      window.removeEventListener('scroll', handleScroll)
    }
  }, [])

  return (
    <Header>
      <h1>Header!</h1>
    </Header>
  )
}

const Header = styled.header`
  // Somehow change the backgound color if window.pageYOffset is greater than value.
  background: ${({color}) => color ? "red" : "blue"};
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 99;
`

Here's a CodeSandBox, forks are appretiated! :)


Solution

  • Store the scroll offset:

    function handleScroll() {
      setScrollY(window.pageYOffset);
    }
    

    Pass color to your styled component:

      return (
        <Header color={scrollY > 1}>
          <h1>Header!</h1>
        </Header>
      )
    

    To change several properties at once, you can import {css} from styled components:

    import styled, { css } from 'styled-components';
    
    // Define a pure group of css properties
    const blueLook= css`
        background-color: #0000ff;
        color: #fff;
    `
    
    // Reuse blueLook inside a styled component
    const Header = styled.header`
      ${props => props.color && blueLook}
    `;