Editable targets

Mix keyboard navigation with text fields, selects and sliders. Editable controls keep their native keys while the arrows move between the rows around them.

Movement bindings leave editable fields their native keys. Arrows can move a caret or change a value, and letter bindings do not capture typed text. Modified focus shortcuts are the exception.

Arrow between the demo's rows, then Tab into a control. Text fields keep their editing behavior, Font size keeps its slider keys, and ↓ on the checkbox moves to the next row. The readout shows navigation in indigo and keys left to the browser in gray.

Live · settings
<ul id="settings">
  <li data-keyrove-item tabindex="0">
    <label>
      <input type="checkbox" checked />
      Email notifications
    </label>
  </li>
  <li data-keyrove-item tabindex="0">
    <label>
      Display name
      <input type="text" value="Ada" />
    </label>
  </li>
  <li data-keyrove-item tabindex="0">
    <label>
      Font size
      <input type="range" min="12" max="24" value="16" />
    </label>
  </li>
  <li data-keyrove-item tabindex="0">
    <label>
      <input type="checkbox" />
      Weekly digest
    </label>
  </li>
  <li data-keyrove-item tabindex="0">
    <label>
      Signature
      <textarea rows="2">Sent from my keyboard</textarea>
    </label>
  </li>
</ul>

No extra configuration is needed. A row remains the current item while focus is inside one of its controls. When navigation resumes, it starts from that row.

Which elements are editable

The test is on the event's target and its ancestors:

  • a textarea or a select;
  • a [contenteditable] element and everything inside it, except a contenteditable="false" island, which opts back out;
  • an input of any type other than button, checkbox, color, file, image, reset and submit.

The input list is drawn by what the bound keys do natively. Arrows move a caret in a text field, step a number, slide a range and move between radio buttons; on a checkbox or a button they do nothing, so navigating from one takes nothing away. That is why ↓ on Email notifications moves rows while ↓ on Font size nudges the slider.

By target, not by key

The target determines whether movement keys are handled. In a text field, ctrl+ArrowRight still moves by word and KeyJ still types "j", even when those combos are bound to navigation. keyRove returns null, so any handler chained after it also receives the event.

The one exception

A focus key with Ctrl, Alt or Meta can move focus from an editable field. Bare keys and Shift-only combinations remain available for typing. Choose shortcuts carefully: some modifiers also produce text, including AltGr reported as Ctrl+Alt.

Typeahead never captures typing inside a field.

While an input method composes

While isComposing is true, keyrove leaves every key to the input method, including modified focus shortcuts. This lets users navigate candidates and finish entering text.

Rows as tab stops

Each row here carries tabindex="0" so it can be focused apart from its control, which is what lets a row be the position before Tab reaches the control inside. It also doubles the tab stops. Put roving tabindex on the rows and the list costs one stop, with the controls keeping theirs. Or make the controls the items, <input data-keyrove-item type="checkbox">, and the rule reads the same way round: the checkboxes navigate, the text fields do not.

Search documentation

↑ ↓ to selectEnter to openEsc to close