Scrolling Frameborder

More fun questions! This time, I’ve been asked to add a black border around the in-browser-view of the site, but when certain components scroll into view, the border needs to change (sometimes to transparent, sometimes to white). I think the best way to do this would be to update the state variable but being new-ish to React, I’m not sure how to do that while using Frontity. Thanks!

EDIT: These are my components:


When the clientIntro component scrolls into view (the yellow component) on this page: https://fortstudio2019.now.sh/what-we-do/
The border goes from black to nonexistent and then to black again once the user scrolls past it to the grid below.

You can use our useInView hook which uses the Intersection Observer underneath.

You have to install @frontity/hooks in your project and then import it using:

import useInView from "@frontity/hooks/use-in-view";

It returns an array with

  • A boolean variable that is true when the HTML enters the screen and false when it leaves
  • A ref to attach to the HTML element that you want to use to control the boolean variable.

You can pass an object of options with the rootMargin that will be passed down to the intersection observer and an onlyOnce property in case you want it to trigger only the first time (it never goes back to false).


In your case, you can create a ClientIntro component that uses an action to set some part to the state to a certain value when it enters the screen.

Create the state and the action:

export default {
  state: {
    theme: {
      // other state...
      clientOnScreen: false
    }
  },
  actions: {
    theme: {
      setClientOnScreen: ({ state }) => isVisible => {
        state.theme.clientOnScreen = isVisible;
      }
    }
  }
}

Create the component that triggers the change:

const ClientIntro = ({ actions, children }) => {
  const [isVisible, scrollRef] = useInView({
    rootMargin: "100px",
    onlyOnce: false
  });

  // When isVisible changes, we trigger an action to update the state.
  React.useEffect(() => {
    actions.theme.setClientOnScreen(isVisible);
  }, [isVisible]);

  return (
    <div ref={scrollRef}>
       {children}
    </div>
  );
};

export default connect(ClientIntro);

Finally, consume the state somewhere else in your app:

const BorderContainer = ({ state, children }) => (
  <Border isVisible={state.theme.isVisible}>
    {children}
  </Border>
);

export default connect(BorderContainer);

const Border = styled.button`
  color: ${props => props.isVisible ? "red" : "blue";
`

I have no idea how to create a border around the in-browser-view (I’m really bad with CSS!) so I wrote the example with a normal button, but I hope you get the idea. Maybe someone else can help with that :slight_smile: