Let's 'Focus' on 'Forms'

Let's 'Focus' on 'Forms'

A deeper look into form and focus event handling

Up until now , we have explored event handling mechanisms for basic i/o devices like keyboard and mouse. Now it is time to move up the food chain.

In this article, we are going to brush up on 2 types of events. Form and Focus.

Following is the codepen for reference code.

Form events

Forms are the important structure for most web applications and thus form handling becomes an important aspect of web development. I am going to cover form handling in a separate article. For now, I want to focus on events related to forms.

There are 3 events related to forms in Javascript.

  1. submit
  2. formdata
  3. reset

1.submit

This event occurs when a user submits any form on the web page. A form submission happens through one of the 3 ways.

  1. When the user presses 'enter' on an input field in the form.
  2. When the user presses any 'button' in the form.
  3. When the user presses an input of type 'submit'.

These actions indicate that the form has been filled up and is now ready to be submitted to the server. To indicate this action, a 'submit' event is fired and a callback attached to the listener is invoked.

SubmitEvent.submitter

SubmitEvent interface defines the event object used in this event. This object is passed as an implicit argument to the callback of the event listener.

submitter represents an HTML element used to submit the form. A button, an input of type submit, etc.

2. formdata

This event occurs when formdata is constructed. i.e. when new FormData() is called. Usually, when a form is submitted to the server, it is sent via XMLHttpRequest. The object sent in the payload is of type FormData.

This object consists of key-value pairs of form fields and values. With this event in place, we can separate the following tasks, handling the form submission in submit handler and submitting it to the server in formdata handler.

FormDataEvent.formData

FormDataEvent interface defines an event object used in this event. This object is passed as an implicit argument to the callback of the event listener.

formData represents the form details provided by the user in a key-value structure.

3. reset

This event occurs when the form is reset. When the user presses on input or button of type="reset", all form fields are cleared and the reset event is fired.

There is no special interface for this event hence no special properties on the event object.

Focus events

When an HTML element is about to receive some kind of data, they are said to be in the focus state. Most elements give some kind of visual feedback by default when they are focused. That is how we come to know which part of our page is active at this moment. We can also set/remove focus from/to an element programmatically with the help of Javascript.

Focus management is also important from an Accessibility point of view. Many people need to use assistive tools (such as a ScreenReader) for web page navigation. As a developer, we need to take adequate care of focus management of our web pages to help assistive tools to perform better.

In addition to this, it is a common practice to implement EVENT DELEGATION for focus management to achieve performance optimization.

For all this, we should get familiar with the focus events and some concepts around them. There are a total of 4 focus events as shown below.

  1. focusin
  2. focus
  3. focusout
  4. blur

Event Order

As per specification, the event order for focus events can be checked here.

Note: I have observed that this event order is not followed by Chrome 90(Ubuntu). You can check it by running the codepen above on your browser.

FocusEvent.relatedTarget

FocusEvent is the interface used by the event object of all focus events. This interface has a property called relatedTarget. It holds the reference to an HTML element which is the secondary target in a focus event. It can also be null.

The secondary target is different in the case of different focus events. You can see its value in the browser console when you run the codepen.

1. focusin

This event is fired when an element is just about to receive the focus. Unlike focus event, this event bubbles. We can make use of this fact in Event Delegation. relatedTarget is null if the element is the first element to receive the focus on this page. Else, it holds the reference to the element from which focus has shifted to this element.

2. focus

This event is fired after an element has received the focus. This event does not bubble up the chain. relatedTarget is the same as for focusin.

3. focusout

This event is fired when an element is about to lose focus. This event too bubbles up and we can use it in Event Delegation along with focusin. relatedTarget holds the reference to the element to which focus is shifting from the current element.

4. blur

This event is fired when an element has lost the focus entirely. This is the last event to be fired among all 4 focus events. relatedTarget is the same as focusout.

Event Delegation for Focus events

You can find my article on Event Delegation here. Focus management presents a great use case for event delegation.

<form id="loginForm">
  <input id="username" type="text" />
  <input id="password" type="password" />
  <button id="submit">Submit</button>
</form>

Consider we have a simple form as shown in the snippet above. Now we want to add some visual effects to each form field when it is focused. Let's say we want to add some border or box-shadow.

We can go ahead and add 3 focus event listeners, 1 for each form field, and write almost the same code in all 3 listeners. This will work for such a simple form. What if we have 15 different input fields in a form? Or better yet, what if we do not know the number of form fields beforehand?

Event delegation helps us in this situation. Event delegation allows us to write only 1 event listener at the parent level, in our case, form. This can be done in 2 ways.

1. Using focus event in CAPTURE phase

As stated earlier, the focus event does not bubble. Thus, the only time we can catch focus events (at form level) that originated from an individual child is in the CAPTURE phase.

Learn more about Event Phases

Consider the code snippet below.

const loginForm = document.getElementById('loginForm');
loginForm.addEventListener('focus', function(e){
  const target = e.target;
  if(target.id === 'username'){}
  else if (target.id === 'password') {}
  else if (target.id === 'submit') {}
}, true);

By sending the third parameter as true, we can set up a focus event listener in the capture phase. Now all focus events of the input fields will always pass through this listener where we can identify individual input fields using the target property on the event object and act accordingly.

2. Using focusin event in BUBBLE phase

On the other hand, we can make use of focusin event, as this event bubbles up. That means a focusin on the username field can be listened to by a focusin listener set up at loginForm level.

const loginForm = document.getElementById('loginForm');
loginForm.addEventListener('focusin', function(e){
  const target = e.target;
  if(target.id === 'username'){}
  else if (target.id === 'password') {}
  else if (target.id === 'submit') {}
});

Using this technique we can also delegate blur/focusout events to the loginForm level.

Finally...

Hope you feel pretty confident by now with the whole EVENT management system of Javascript DOM.

In the next article, we are going to see some more interesting events like these.

Stay tuned...