Mind the `document.activeElement`!
Tags: javascript, shadowdom, a11y, html
Published: 2020-02-19 00:35:51

The element that currently has _focus_ in your HTML at any point in time can be accessed as `document.activeElement`. If you don't know, now you know!

What's more, while it can be difficult to capture the value of this property while debugging, at least without changing it, you can leverage browsers that allow you to ["watch live expressions"](https://developers.google.com/web/tools/chrome-devtools/console/live-expressions) to keep the current value of this property available at all times, 😱. No, really, go check it out right now!

There are lots of ways you can leverage this in your work, whether in functional code, unit tests or debugging, but I'm not looking to walk you through all the things that should be, can be, or will be in this area. However, if you're already using this value, I'd love to hear more about it in the comments. My usage can definitely be super-powered by hearing great workflows from others, so I look forward to hearing what you've got up your sleeves.

![This isn't the `document` you're looking for...](https://dev-to-uploads.s3.amazonaws.com/i/6l89soeupyn2bdpudjau.jpg)

We are gathered here, today, to go a little bit deeper on what `document` means and when _the_ `document` isn't the “document”0 you're looking for and what to do in that case.

## Out of the shadows a new `document` rises...

Do you find yourself using code like the following to attach a shadow root to elements in your application?

```js
el.attachShadow({mode: 'open'});
```

Do you find yourself attaching that shadow root to custom elements that you've defined?

```js
class CustomElement extends HTMLElement {}
customElement.define('custom-element', CustomElement);
```

Then you're already using web components.

If not, I highly recommend them in many and varied use cases! The benefits I've gained from working with custom elements and shadow DOM from well before both APIs were even supported by two browsers, [let alone all of them](https://twitter.com/polymer/status/1217578939456970754), are all positive, and the full possibilities of this sometimes wholely different paradigm of client-side development are still only beginning to be fully explored.

{% twitter 1217578939456970754 %}

If you're ready to start exploring them too, check out [Web Components: from zero to hero](https://dev.to/thepassle/web-components-from-zero-to-hero-4n4m), an amazing introduction to these technologies by [Pascal Schilp](https://dev.to/thepassle), and you'll be well on the way.

When creating your own custom element with their own shadow roots, you're getting a "DOM subtree that is rendered separately from a document's main DOM tree". A subtree that is separate from the `document`: a `document` to itself. Inside of that subtree, you get encapsulation for whatever DOM lives therein from external selectors, a special HTML `slot` API for composing DOM from the outside of the element, and much more. However, when minding the `document.activeElement`, it is important to look a little deeper at the specific cost that we pay to get these new capabilities.

`document.activeElement` points to the element in the `document` that currently has _focus_, but what happens when that element isn't actually in the `document`? If your shadow DOM has focusable elements internal to it, and one of those elements currently has _focus_, `document.activeElement` (like all other selectors) will not be able to point directly to it. What it will point to is the first element in the `document` that includes a shadow DOM. So, taking the following tree into account:

```html
<document>
  <body>
    <h1>Title</h1>
    <custom-element>
      #shadow-root
        <h2>Sub-title</h2>
        <other-custom-element>
          #shadow-root
            <a href="#">This is a link</a> <!-- The link _has_ focus -->
```

When the `<a>` element above is focused and `document.activeElement` is referenced, the value returned will point to the `<custom-element>` just below the `<h1>`; not the `<a>`, not the `<other-custom-element>` that is its parent, and likely, not what you expected. 

## A brave new world

> Oh no, shadow DOM broke the internet!
> <cite>- alarmist JS (framework) user</cite>

Well, in a word, "no".

With more nuance... shadow DOM has broken the assumption that the specifics of _focus_ in any one component will bleed into all other components, so yes the fragile, fly by night, shoot from the hip internet that was previously the only option available to use is _broken_ if you choose to use shadow DOM and the shadow boundaries that they create. However, if you choose to use shadow DOM and the shadow boundaries that they create, you now have access to a more nuanced, controllable, and refined DOM than ever before. Yes, some things that you may have taken for granted in the past may be a little different than you remember, but you also have access to capabilities that were previously impossible or prohibitively complex.

> But... if I can't see what the currently focused element is, what _will_ I do?

While inside a shadow root, `document.activeElement` will not allow you to see if any other elements in the subtree are currently focused, yes. However, from the root of a subtree, we now have `shadowRoot.activeElement` available to us when we desire to find the focused element in our current subtree. This means that instead of having to worry about the entire document (both above and below your current component), you can take into consideration only the DOM belonging to the subtree related to the current component.

## OK, how do I leverage this?

I feel you start to think, "ok, that sounds like I could find a way to process this as being cool after ruminating on it for a while, but how do I figure out what shadow root I'm in?", and that's a great question! The answer is in the `getRootNode()` method that has been added to `Element` as part of the introduction of shadow DOM. With this method, you will be given the root of the DOM tree in which the element you called `getRootNode()` on lives. Whether what is returned is the actual `document` or an individual `shadowRoot` its member property `activeElement` will allow you to know what element in that tree is currently focused.

Let's revisit our sample document from above to better understand what this means...

```html
<document>
  <body>
    <h1>Title</h1>
    <custom-element>
      #shadow-root
        <h2>Sub-title</h2>
        <other-custom-element>
          #shadow-root
            <a href="#">This is a link</a> <!-- The link _has_ focus -->
```

When you have a reference to the `<a>` element therein:

```js
const root = a.getRootNode();
console.log(root);             // otherCustomElement#shadowRoot
const activeElement = root.activeElement;
console.log(activeElement);    // <a href="#"></a>
```

When you have a reference to the `<h2>` element therein:

```js
const root = h2.getRootNode();
console.log(root);             // customElement#shadowRoot
const activeElement = root.activeElement;
console.log(activeElement);    // <other-custom-element></other-custom-element>
```

And, when you have a reference to the `<body>` element therein:

```js
const root = body.getRootNode();
console.log(root);             // document
const activeElement = root.activeElement;
console.log(activeElement);    // <custom-element></custom-element>
```

## But, a component _should_ have some control of its children, right?


I completely agree! But, in the context of a free and single `document` "some" control becomes _complete and total_ control.

![Not just "some" control...](https://dev-to-uploads.s3.amazonaws.com/i/r4krolxrj2ncaiigf02p.jpg)

In the case of shadow DOM encapsulated subtrees, the control that a parent has over its children is only the control that said child offers in the form of its public API. If you don't want to cede any control to a parent element implementing your custom element, you do not have to. Much like the first night you stayed out past curfew, this will surprise most parents accustomed to a level of control they maybe never should have had. 

- Will they get the number to your new cell phone?
- Will you pick up when they call?
- Will you still come home for dinner on Sunday nights?

All these questions and more are yours to answer via the attributes, properties, and methods that your elements surface to the public. Take care to respect your parents, but don't think that you have to become a doctor/lawyer/the President just because your mother said you should.

## The components are alright

In this way, we might address the following simplification of the DOM we've reviewed through much of this article:

```html
<document>
  <body>
    <h1>Title</h1>
    <other-custom-element>
      #shadow-root
        <a href="#">This is a link</a> <!-- The link _has_ focus -->
```

When accessing `document.activeElement` from the outside, again we will be returned `other-custom-element` in reverence of the constrained control we now have over our once singular `document`. In this context, we may want to forward a `click` event into our focused element, however not having direct access to the anchor tag through the shadow boundary, we'd be calling `click()` on `other-custom-element`. By default, this type of interaction on the shadow DOM of `other-custom-element` would be prevented. In the case that we wanted this sort of thing to be possible, we could build the following extension of the `click()` method into our `other-custom-element` element to pass the `click` into its child:

```
click() {
  this.shadowRoot.querySelector('a').click();
}
```

But what about the case where there are more than one anchor tags inside of an `other-custom-element`?

```
<other-custom-element>
  #shadow-root
    <a href="#">This is a link</a>
    <a href="#">This is also a link</a> <!-- The link _has_ focus -->
```

In this case, we can take advantage of the `activeElement` accessor on a shadow root and target the correct anchor tag as follows to make an even more flexible custom element implementation:

```
click() {
  this.shadowRoot.activeElement.click();
}
```

From here, there are any number of next steps that you can take to produce your own powerful custom elements that leverage the encapsulation offered by the shadow DOM to structure more nuanced, yet eminently powerful APIs to surface to users of your components. As you find patterns that work well for you, I'd love to hear about them in the comments below. If you're interested in uses of the `activeElement` property in the wild, I invite you to checkout [Spectrum Web Components](https://opensource.adobe.com/spectrum-web-components/) where we are actively reviewing the use of this and many other practices to power our growing web component implementation of the [Spectrum](https://spectrum.adobe.com/), Abode's design system.