Control HTML Focus from Rails Server

by Kim Laplume

Summary

An easy way to control the focus of DOM-elements from Rails

Lesson

Sometimes, it is important to control exactly which DOM-element is focused after a user interaction. For a project of mine, I implemented keyboard controls and wanted to keep the focus on a given node after moving it down or up, triggering a HTTP request to Rails to render the reordered elements (in a Turbo Frame), that was morphed from a Turbo Stream Action. Initially I was trying to listen for some event trigger after the form submission or the morphing was done, but couldn't get the job done. Then I remembered custom Turbo Stream Actions and made this work in a breeze.

In your Javascript, define a custom action like this

import "@hotwired/turbo-rails"

Turbo.StreamActions.focus = function () {
  const target = this.getAttribute("target")
  const focusElement = document.querySelector(target)
  if (focusElement) focusElement.focus()
}

Then, in your response that you send back from the server, include your Custom Stream Action, e.g.

<turbo-stream action="focus" target='[data-uuid="<%= @workitem.uuid %>"]'></turbo-stream>

In the example above, I'm targeting a unique node with the HTML attribute data-uuid="<something>", but the Stream Action is very versatile and can be used for other situations as well.