Use Vim Keyboard Shortcuts on your Blog
Tags: svelte, webdev, javascript
Published: 2021-10-18 09:48:38

---
title: "Use Vim Keyboard Shortcuts on your Blog"
published: "true"
description: "Use Vim keyboard shortcuts on you blog: how to make it easy for Vim users to jump around your Svelte blog site with a keyboard and no mouse!"
tags: "svelte, webdev, javascript"
canonical_url: "https://rodneylab.com/vim-keyboard-shortcuts-blog/"
cover_image: "https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ocwcu25twm9kdvodh3ox.png"
---


## ⌨️ Adding Vim Keyboard Navigation to you Blog Posts

Let's look at how to use Vim keyboard shortcuts on your blog.  Although the Vim text editor first appeared in the late 20th century, it is still enjoys some popularity.  The Stackoverflow 2021 Devleoper Survey results show <a aria-label="Open Stack Overflow survey results" href="https://insights.stackoverflow.com/survey/2021/#most-popular-technologies-new-collab-tools-prof">24% of developers use Vim and another 5%, Neovim (a younger alternative)</a>.  I personally use Vim for dev work and end up finding myself trying to use Vim keyboard shortcuts outside of the editors towards the end of long days spent coding!  Completely selfishly, why not make life easier for Vim developers to get around your blog posts?

In this post we see how you can modify a Svelte blog site to respond to some Vim keyboard shortcuts.  We'll clone the <a aria-label="Open the Svelte Kit blog M D sveX starter in Git Hub" href="https://github.com/rodneylab/sveltekit-blog-mdx">SvelteKit Blog MDsveX Starter</a> to get things going quicker.  Then we will create a new component for responding to keyboard shortcuts and add that to the existing blog post template.  If you are not yet familiar with SvelteKit, you can still follow along.  If you don't like Svelte then the code can also be adapted for use on React or plain HTML/JavaScript sites.  Why don't we press on?

## 🔑 Start your Engines!

Let's start by cloning the starter and spinning up our development server:

```shell
git clone https://github.com/rodneylab/sveltekit-blog-mdx.git vim-shortcut-blog
cd vim-shortcut-blog
pnpm install
cp .env.EXAMPLE .env
npm run dev
```

If this is your first time using the stater, have a poke around the folders and then jump to <a href="http://localhost:3000/" >localhost:3000</a> to get used to it.  If you already have something running on TCP port 3000 <a aria-label="Open post on getting started with SvelteKit" href="https://rodneylab.com/getting-started-with-sveltekit/#changingSvelteKitDevServerPort">check out the post on getting started with SvelteKit</a> to see how to switch ports.

## 🧱 Use Vim Keyboard Shortcuts on your Blog: Building our Site

Let's create the `VimKeyboardShortcuts` component.  Although we will create it as a Svelte component, it will not render anything, just react to key presses.  Paste this code into a new file `src/lib/components/VimKeyboardShortcuts.svelte`:

```html
<script>
  import { onDestroy, onMount } from 'svelte';
  import { browser } from '$app/env';
 
  onMount(() => {
    if (browser) {
      document.addEventListener('keydown', handleKeyDown);
    }
  });
 
  onDestroy(() => {
    if (browser) {
      document.removeEventListener('keydown', handleKeyDown);
    }
  });
 
  let gAlreadyPressed = false;
 
  function viewportHeight() {
    return window.innerHeight;
  }
 
  function handleKeyDown(event) {
  }
</script>
```

This is just a shell, we will flesh it out soon.  This shell let's us see a few Svelte features.  In line `7` we add a an event listener, which is what allows us to detect that a key has been pressed.  Event listeners run in the background until they are removed.  So to use it in Svelte, we add the event listener when our component is created and then remove it when the component is destroyed (e.g. user navigates to another page).  In Svelte the `onMount` and `onDestroy` functions let us run code when the component is created and destructed. Here we only need to listen for the `keydown` event but you can listen for other events, just adding additional `addEventListener` lines.  Note the event listener calls our `handleKeyDown` function which we are yet to fill out.


We will use `gAlreadyPressed` to listen for a repeat press of the `g` key (as in the `gg` shortcut which takes us to the top of the page).  Finally we have a utility function to calculate the viewport height.  This is the inner window browser window height.  We will use this to scroll up or down by half a screen.

That's the shell. Before we flesh it out, let's add the component to our blog post template.

### Integrating `VimKeyboardShortcuts`

Update the `BlogPost` component (`src/lib/components/BlogPost.svelte`)  as below.  This is the template used to render blog posts

```Z7=&|;Tvh^$>9/U`t7Wf>yD0,
<script>
  import readingTime from 'reading-time';
  import BannerImage from '$lib/components/BannerImage.svelte';
  import SEO from '$lib/components/SEO/index.svelte';
  import VimKeyboardShortcuts from '$lib/components/VimKeyboardShortcuts.svelte';
 
  export let imageData;
```

```
<SEO
  article
  {breadcrumbs}
  {slug}
  {title}
  {datePublished}
  {lastUpdated}
  {metadescription}
  {timeToRead}
  featuredImage={featuredImageObject}
  ogImage={ogImageObject}
  ogSquareImage={ogSquareImageObject}
  twitterImage={twitterImageObject}
/>
<VimKeyboardShortcuts />
<BannerImage {imageData} />
<h1>{title}</h1>
```

Now we have the component in the DOM for our blog posts, we just need to fill it out and test it.

### handleKeyDown

Let's jump back to `src/lib/components/VimKeyboardShortcuts.svelte` and add the code for handling key presses:

```html
	  function handleKeyDown(event) {
    const { ctrlKey, key } = event;
    switch (key) {
      case 'd':
        if (ctrlKey) {
          window.scrollBy(0, 0.5 * viewportHeight());
        }
        break;
      case 'G':
        const lastElement = document.getElementsByTagName('main')[0].lastElementChild;
        lastElement.scrollIntoView(true);
        break;
      case 'g':
        if (gAlreadyPressed) {
          const firstElement = document.getElementsByTagName('main')[0].firstElementChild;
          firstElement.scrollIntoView(true);
        } else {
          gAlreadyPressed = true;
          setTimeout(() => {
            gAlreadyPressed = false;
          }, 1000);
        }
        break;
      case 'u':
        if (ctrlKey) {
          window.scrollBy(0, -0.5 * viewportHeight());
        }
      default:
    }
  }
</script>
```

We use a `switch` statement here in the logic for responding to different key presses.  This is a little cleaner than a series of `if` statements.  `switch` is one of those things you might look at when initially learning JavaScript, but then not have much use for in you domain.  So <a aria-label="Open M D N docs on switch" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch">here's the MDN docs on `switch` in case you need to brush up</a>.  Switch cases use strict comparison (`===`).

### Handling a Key Double Press

Let's look at the `g` block in detail (lines `35`&ndash;`45`).  This block handles the shortcut which scrolls to the top of the post.  It is triggered when the user presses `g` twice.  The first thing we do in the block is check if `g` has already been pressed.  If it has, we look for the `main` HTML element (we rely on the post using semantic HTML here).  Next, we find the first child element of the main element. Then finally in line 38, we scroll that element into view.

We get smooth scrolling behaviour because the starter's global CSS includes `scroll-behavior: smooth;` on the `html` element.  You can see this in `src/lib/styles/styless.scss`.

If the user is pressing the `g` key for the first time.  We need to register it, but not do anything else.  We can do that by setting `gAlreadyPressed` to true. However, we really should expect the user to press `g`, for the second time, quite soon after the first time (that's if they intended to execute the shortcut we are listening for).  This means we need to reset `gAlreadyPressed` back to false after, let's say one second.  This is what we do in lines `41`&ndash;`43`, using <a aria-label="Open M D N docs on set Timeout" href="https://developer.mozilla.org/en-US/docs/Web/API/setTimeout">setTimeout</a>.  Our `setTimeout` call waits for 1000 milliseconds before it does anything.  It then executes the anonymous function `() => { gAlreadyPressed = false; }` which we passed in as the first argument.

That's all the logic in now! The other switch are are simpler variations of the one we just went through.  Next we can test it all out.

## 💯  Use Vim Keyboard Shortcuts on your Blog: Testing Everything

Here's a list of the keyboard shortcuts we programmed:

<dl>
	<dt><strong><code>Ctrl + d</code></strong></dt><dd>scroll down half a window height,</dd>
	<dt><strong><code>G</code></strong></dt><dd>scroll to bottom of the post,</dd>
	<dt><strong><code>g g</code></strong></dt><dd>scroll to top of the post,</dd>
	<dt><strong><code>Ctrl + u</code></strong></dt><dd>scroll up half a window height.</dd>
</dl>

Try them out to check all is well.

## 🙌🏽  Use Vim Keyboard Shortcuts on your Blog: What we Learned

In this post we learned:
- how to listen for keyboard events in Svelte,

- listening for key combination presses in JavaScript,

- how to listen for a double key press in JavaScript.

I do hope there is at least one thing in this article which you can use in your work or a side project.  For extensions, you could add shortcuts to jump to the next post if the user presses `l` or, previous post for `h`.  On top you can jump up a level (based on the page breadcrumbs) if the user types `:q`.  The sky is the limit, you can really go to town on this!  For more <a aria-label="Open Vim cheat sheet" href="https://vim.rtorr.com/">Vim keyboard shortcuts Richard Torruellas has a fantastic cheatsheet</a>.  <a aria-label="Open article on Keycodes" href="https://www.freecodecamp.org/news/javascript-keycode-list-keypress-event-key-codes/">For more on Keyboard events, Tapas Adhikary wrote a tremendous freeCodeCamp post</a>.

As always get in touch with feedback if I have missed a trick somewhere! Also, I'm especially keen to hear feedback from users with accessibility needs, as to whether adding these shortcuts has a negative impact on their experience.  

You can see the <a aria-label="Open the Rodney Lab Git Hub repo" href="https://github.com/rodneylab/vim-shortcut-blog">full code for this Vim keyboard shortcut blog site on the Rodney Lab Git Hub repo</a>.

## 🙏🏽 Use Vim Keyboard Shortcuts on your Blog: Feedback

Have you found the post useful? Do you have your own methods for solving this problem? Let me know your solution. Would you like to see posts on another topic instead? Get in touch with ideas for new posts. Also if you like my writing style, get in touch if I can write some posts for your company site on a consultancy basis. Read on to find ways to get in touch, further below. If you want to support posts similar to this one and can spare a few dollars, euros or pounds, please <a aria-label="Support Rodney Lab via Buy me a Coffee" href="https://rodneylab.com/giving/">consider supporting me through Buy me a Coffee</a>.

Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via <a aria-label="Reach out on Twitter" href="https://twitter.com/messages/compose?recipient_id=1323579817258831875">@askRodney</a> on Twitter and also <a aria-label="Contact Rodney Lab via Telegram" href="https://t.me/askRodney">askRodney on Telegram</a>. Also, see <a aria-label="Get in touch with Rodney Lab" href="https://rodneylab.com/contact">further ways to get in touch with Rodney Lab</a>. I post regularly on <a aria-label="See posts on svelte kit" href="https://rodneylab.com/tags/sveltekit/">SvelteKit</a> as well as other topics. Also <a aria-label="Subscribe to the Rodney Lab newsletter" href="https://rodneylab.com/about/#newsletter">subscribe to the newsletter to keep up-to-date</a> with our latest projects.