Where I have a custom component that wraps an input element, I'm trying to ensure that tabindex
is working correctly.
The following code will work for tabbing forward. But tabbing backwards (Shift + Tab
) does not work correctly, it'll focus the outer wrapper x-input
instead.
@customElement('x-input')
export class CustomInput extends LitElement {
@query("input")
private _input: HTMLInputElement;
constructor() {
super();
this.tabIndex = this.tabIndex < 0 ? 0 : this.tabIndex;
this.addEventListener("focusin", this._onFocusIn);
}
render() {
return html`<input tabindex="-1">`;
}
private _onFocusIn(): void {
this._input.focus();
}
}
A full playgound/example can be found here.
Just make use of delegateFocus
property of the shadowRoot
. It would work naturally. You don't need to setup complex focus
event behavior:
import {html, css, LitElement} from 'lit';
import {customElement, query} from 'lit/decorators.js';
@customElement('x-input')
export class CustomInput extends LitElement {
static shadowRootOptions = {
...LitElement.shadowRootOptions,
delegatesFocus: true
};
@query("input")
private _input: HTMLInputElement;
constructor() {
super();
this.tabIndex = this.tabIndex < 0 ? 0 : this.tabIndex;
}
render() {
// The input element is naturally tabbable
return html`<input tabindex="0">`;
}
}
The delegateFocus
will do two things:
:focus
style gets applied to your host/custom element. Read more about the delegateFocus
here. Also this article has a nice explainer about handling focus.