JSFiddle - React, Tailwind, and code Playground

by Graham Dixon

HTML

<ul>
  <li>
    <a id="first" href="#" class='move'>Link</a>
    <ul>
      <li>
        <a href="#" class='move'>Link</a>
        <ul>
          <li>
            <a href="#" class='move'>Link</a>
          </li>
          <li>
            <a href="#" class='move'>Link</a>
            <ul>
              <li>
                <a href="#" class='move'>Link</a>
              </li>
              <li>
                <a href="#" class='move'>Link</a>
              </li>
              <li>
                <a href="#" class='move'>Link</a>
              </li>
            </ul>
          </li>
          <li>
            <a href="#" class='move'>Link</a>
          </li>
        </ul>
      </li>
      <li>
        <a href="#" class='move'>Link</a>
      </li>
      <li>
        <a href="#" class='move'>Link</a>
      </li>
    </ul>
  </li>
  <li>
    <a href="#" class='move'>Link</a>
    <ul>
      <li>
        <a href="#" class='move'>Link</a>
      </li>
      <li>
        <a href="#" class='move'>Link</a>
      </li>
      <li>
        <a href="#" class='move'>Link</a>
      </li>
    </ul>
  </li>
  <li>
    <a href="#" class='move'>Link</a>
    <ul>
      <li>
        <a href="#" class='move'>Link</a>
        <ul>
          <li>
            <a href="#" class='move'>Link</a>
          </li>
          <li>
            <a href="#" class='move'>Link</a>
            <ul>
              <li>
                <a href="#" class='move'>Link</a>
              </li>
              <li>
                <a href="#" class='move'>Link</a>
              </li>
              <li>
                <a href="#" class='move'>Link</a>
              </li>
            </ul>
          </li>
          <li>
            <a href="#" class='move'>Link</a>
          </li>
        </ul>
      </li>
      <li>
        <a href="#" class='move'>Link</a>
      </li>
      <li>
        <a href="#" class='move'>Link</a>
        <ul>
          <li>
            <a href="#" class='move'>Link</a>
          </li>
...

CSS

a.focus {
  text-decoration: underline;
}

a {
  text-decoration: none;
}

JavaScript

$(document).keydown(
  function(e) {
    // Down key or right key
    if (e.keyCode == 40 || e.keyCode == 39) {
      if ($("a.focus").closest('li').find("ul>li").length > 0) {
        $("a.focus").removeClass('focus').closest('li').find("ul>li").find('a').first().addClass("focus");
      } else if ($("a.focus").closest('li').next().find('a').length > 0) {
        $("a.focus").removeClass('focus').closest('li').next().find('a').first().addClass("focus");
      } else {
        if ($("a.focus").closest('li').parents('ul').parents('li').next().find('a').length > 0) {
          $("a.focus").removeClass('focus').closest('li').parents('ul').parents('li').next().find('a').first().addClass("focus");
        }
      }
    }
    // Up key or left key
    if (e.keyCode == 38 || e.keyCode == 37) {
      if ($("a.focus").closest('li').is("li:first-child")) {
        if ($("a.focus").closest('li').parent('ul').parent('li').length > 0) {
          $("a.focus").removeClass('focus').closest('li').parent('ul').parent('li').find('a').first().addClass("focus");
        }
      } else if ($("a.focus").closest('li').prev().length > 0) {
        if ($("a.focus").closest('li').prev().find('ul>li').length > 0) {
          $("a.focus").removeClass('focus').closest('li').prev().find('ul>li').find('a').last().addClass("focus");
        } else {
          $("a.focus").removeClass('focus').closest('li').prev().find('a').first().addClass("focus");
        }
      }
    }
  }
);

$('.move').click(function() {
  $("a.focus").removeClass('focus');
  $(this).addClass("focus");
});

$(function() {
  $("a.focus").removeClass('focus');
  $('#first').addClass("focus"); // Init focus on first link
});