Implemented ‘j’ and ‘k’ shortcuts on the main blog index today, to move forward and back through posts.
Gatsby uses a template file to create each page of posts (
/src/templates/blog-index.js); those created pages in turn call a React component to “unroll” and display each set of posts sent to them in props. I cleverly called it
To implement the shortcuts I changed
Posts to be a stateful component. The state holds an array called
visible, intended to indicate which posts are currently in the viewport.
I added the
react-scroll module (here), and set it up inside componentDidMount, along with a keydown listener on
window. So… when the component is mounted in the browser, there’s a function watching keypresses, and a pair of functions watching
Then I implemented
react-intersection-observer. Each post’s code is wrapped in an
Observer. When the observer enters the viewport, it fires a function adding it’s index # to
this.state.visible. When it leaves the viewport, the same function filters it back out of the array. It makes more sense, maybe, if you console.log that array while scrolling on the page — the array goes from  to [0,1] to  to [1,2]… then there are 2 short posts in a row, all at least partially in the viewport, so it goes to [1,2,3], before dropping back to [2,3].
The keypress function calls scroll, when ‘j’ or ‘k’ is pressed. If the user presses ‘j’,
react-scroll goes to the second number in the array (if the array has multiple numbers) or to the next number after the sole number in the array. So… if a half a post is on the top, and the next one in the middle of the viewport, the “middle post” scrolls to the top. If only one post is in the viewport, the next post scrolls up.
If the user presses ‘k’, the whole thing happens more or less the same, in reverse.
There are some edge cases where this process isn’t perfect, and I hope to improve upon it, but it’s not bad, considering. N.B., only after I put this together did I learn that there’s a fairly well-supported DOM method called scrollIntoView that might be part of a more perfect solution. TBD…