When you use a site on a regular basis it is nice to have keyboard shortcuts to make navigation easy. A week ago we added support to DNSimple for various keyboard shortcuts to make your life easier. Here is a short explanation on how to use them and how we implemented them.

The Keyboard Shortcuts

First you can pull up a help dialog at any time by pressing ?. This dialog will show the keyboard shortcuts that are available to you. Some shortcuts might be context sensitive and some will work throughout the entire site. You may close this dialog by pressing ? again.

j and k will be familiar to VIM users. These keystrokes are used to move up and down in lists. Right now these work in the domain list page and on the contact list page.

Whenever an item is highlighted using the j and k keys you may press return to go to either view the entry (for the domain list) or edit the entry (for the contact list). If you pass the end of the list and there are additional pages then you will move forward or backward to the next or previous page. You may also use n to move to the next page or b (or p) to move to the previous page.

J and K (capitalized versions of the above) will move you to the top and bottom of the list, respectively.

/ or S (capital S) will focus on the domain list search box. F will focus on the domain list filter drop down.

On the domain list page or the domain view page you may type s to go to the domain's one-click services page. e will jump to the advanced editor for the current domain.

There are also key combinations that can be used to navigate around the site. For example, g d will go to the domain list and g c will go to the contact list. You can also use d n to add a new domain.

How Did we Do it?

Most of the magic comes from the awesome Mousetrap library from Craig Campbell. We use Coffescript, so the samples below will be shown in Coffeescript.

First, a simple binding example:

Mousetrap.bind(['g d', 'd l'], () ->
  location.href = "/domains"
)

This tells Mousetrap to bind the two key combinations g d (g followed by d) and d l (d followed by l) to an anonymous function that sets the current page location. It's a simple way to navigate that is nice for global URLs.

Mousetrap.bind(['S', '/'], () ->
  $("#domain-search").focus()
  return false
)
Mousetrap.bind('F', () ->
  $("#domain-filter").focus()
)

In this example keystrokes are used to set the focus. In the first binding the focus is set on the #domain-search. The function returns false so that the character is not actually entered into the search field (by default it would be). The focus on the domain filter doesn't need to do the same since it is a drop-down select.

Highlighter

Finally, here's how I implemented row highlighting.

First, the highlighter function:

highlighter = (current, next) ->
  if next > 0 && next <= totalRows
    $("table.table-hover tbody tr:nth-child(#{current}) td").removeClass("highlight")
    rowToHighlight = $("table.table-hover tbody tr:nth-child(#{next}) td")
    rowToHighlight.addClass("highlight")
    $('html, body').animate(scrollTop: rowToHighlight.offset().top - 200, 200)
    currentRow = next
  else if next > totalRows && $(".next a").size() > 0
    location.href = $(".next a").attr("href")
  else if next <= 0 && $(".previous a").size() > 0
    location.href = $(".previous a").attr("href")

This function takes the current, highlighted index and the next index and either highlights the "next" row or moves to the next or previous page if you're at the top or bottom.

This function is then attached to Mousetrap as follows:

totalRows = $("table.table-hover tbody tr").size()

Mousetrap.bind('j', () ->
  highlighter(currentRow, currentRow + 1)
)
Mousetrap.bind('J', () ->
  highlighter(currentRow, totalRows)
)
Mousetrap.bind('k', () ->
  highlighter(currentRow, currentRow - 1)
)
Mousetrap.bind('K', () ->
  highlighter(currentRow, 1)
)

Conclusion

Keyboard short cuts can be a wonderful time saver and they're easy to implement with Mousetrap. I highly recommend taking a look at the excellent Mousetrap documentation and seeing if keyboard shortcuts fit into your app as well.