Premise
Sometimes your application requires validating user input in real time. In order to maximize user experience, for example, you might want to report whether a certain email address, time slot etc. has been taken.
We are going to explore how this can be achieved just with native Turbo Frames form submission handling and a few client-side event hooks.
Starting Point
Let’s explore the server side code first. I’ve again replicated a basic Rails controller in Node.js again. The /subdomain/edit
route uses the form.html
template to return, you guessed it, the form. It’s populated with the current value, whether that value is invalid
, and a helper
text:
https://stackblitz.com/edit/turbo-typeahead-validation?file=index.js%3AL21
Emulating an update
action, we respond to a PATCH request on /subdomain
with either 200 (OK) or 422 (Unprocessable Content) depending on whether the subdomain we entered is contained in a list of taken subdomains:
https://stackblitz.com/edit/turbo-typeahead-validation?file=index.js%3AL42
Continuing to the client, our index.html
only contains a reference to an eager loaded Turbo Frame pointing to said /subdomain/edit
route:
https://stackblitz.com/edit/turbo-typeahead-validation?file=index.html%3AL41
I’ve also included an event handler that listens for the input
event of the text field and sets off a form submission:
https://stackblitz.com/edit/turbo-typeahead-validation?file=app.js%3AL10
Note: In reality you’d likely want to debounce this to save bandwidth and not overload your server.
Challenge
Currently the form is practically unusable because the text field loses focus and we have to manually click into it again. We could use autofocus
but that leads to other issues down the road (trust me on this one).
Your task is to
- somehow capture and store the
activeElement
(the one with focus, i.e. the text field), - and the current caret positition on
turbo:submit-start
- and restore both on
turbo:frame-render
.
Here’s a preview of the result:
Caveat
You will learn why morphing libraries such as Idiomorph or morphdom require IDs being set on HTML elements 😉.
Teaser
What would it take to make this solution portable, for example in a Stimulus controller?