Sometimes you need to take users to where you want them to be.

If you've got a form with lots of fields, you might have a requirement to put the cursor in a specific field. That's called putting focus on that field.

So when the user starts typing, the characters show up in the focused field.

You get the idea.

It's not hard to put focus on the first field in the form by default. You can just use autofocus.

And users put focus on different fields by tabbing from one field to the next. That's how they do it manually.

But, like I said, on some occasions you might need to tell the UI: "Hey, put the focus on this field. Right now."

That's what I'm going to show you how to do in this guide.

Going Old School

There are a few ways to skin this cat. 

In this particular case, I need to put focus on a field that's created by a third-party component. It was imported from a separate module.

So I could mucking go about in the template associated with the component I'm using. Or I could just grab HTML info from the template and use my own component to put focus on the correct element.

I chose the latter. I recommend you do the same.

It all comes down to this: I need to find an element by its class name and put the focus there.

For that, I'll go old school by using the Document Object Model (DOM). That seems like the best way to find an element by class name.

The Code Itself

Take a look at the relevant code here:

  @HostListener('document:keyup', ['$event'])
  handleKeyboardEvent(event: KeyboardEvent) {
    if (event.key == 'Tab' && this.lastField == 'subject') {
      let el: any = document.querySelectorAll('.ql-editor')

      if (el && el.length == 1) {
        el[0].focus();
        this.lastField = 'body';
      }
    }
  }

I've covered the @HostListener aspect of that block in a previous guide. For now, hone in on the contents of that first if statement.

As I mentioned above, I'm using DOM here so that's why you see a reference to the document object. Specifically, the application invokes the querySelectAll() method from that object.

That method returns a NodeList of elements that match the criteria specified in the parentheses.

In this case, the query is a class named "ql-editor." That dot notation you see in front of "ql-editor" is the dead giveaway that the application is searching for a class with that name.

So that method will search the entire DOM tree and return an array (NodeList) of elements that match the criteria.

Fortunately, there's only one element that matches the criteria in this template. So the array will only include a single element.

But you don't have to search by class name. You can search be element name as well. 

For example:

let el: any = document.querySelectorAll('p')

That will return a NodeList of all <p> elements on the page.

Note that there's no period in front of the 'p'. That's how you know it's searching for an element name and not a class name.

If you'd like to search for an element by its ID, you can do that, too:

let el: any = document.querySelectorAll('#my-id')

Take a look at that hashtag in front of 'my-id.' That's how you know it's searching for an element by ID.

And you can search for elements with specific attributes as well:

let el: any = document.querySelectorAll('div[id]')

That will give you a NodeList of all <div> elements with an id attribute.

But let's get back to the whole point of this guide.

Focusing on Focus

So once you've got the element, how do you put the focus on it?

It's easy. Just use the focus() method as you see in the above code.

The code grabs the first element from the NodeList (there should only be one) and invokes the focus() method.

That's it. 

Really. That's it.

The application will now put the cursor in the field identified by el. In my case, it's in the Quill editor.

But you can code it for whatever element deserves the focus.

Wrapping It Up

Now you know how to find an element and put focus on it. Feel free to use this same method with your own applications.

Although it's unconventional to use DOM references in the component class, it's sometimes necessary. Fortunately, TypeScript makes it pretty easy for us to do that.

So get busy rolling out your own solution.

Have fun!