Home > Enterprise >  How to enable keyboard control for Google's Model Viewer by default?
How to enable keyboard control for Google's Model Viewer by default?

Time:10-12

For accessibility I'm attempting to allow arrow keys to control the camera orbit of my model viewer the moment the poster is dismissed. So far it seems that I'm able to control the camera with the arrow keys, but only if I interact with the model-viewer a second time (i.e. I click to dismiss the poster, then can't manipulate the camera until I click the 3D model at least once). This is bad form for accessibility.

Is there a way to force model viewer to accept keyboard input without needing to click/touch the 3D model at least once? So far I've tried:

  1. Using the focus(); function on my model-viewer element, on my .userInput div within it, and the canvas element within that
  2. Setting the tab indexes of each of these to 1 with no success
  3. Using delegateFocus on my elements
  4. Using the enableInteraction(); function native to model-viewer
  5. Adding an event listener when the poster is dismissed, via this.addEventListener('keydown', this[$modelViewer].value?.onKeyDown);

I've verified that these elements are being manipulated/appended in the correct way, so it appears using focus and tab indexes isn't what allows model-viewer to take keyboard input in the first place.

How can I force model-viewer to accept keyboard input the moment the poster is dismissed and the 3D model is loaded?

CodePudding user response:

You should be able to call .focus() on your .userInput div, the tricky thing is that <model-viewer> creates a Shadow DOM. The purpose of a shadow DOM is to encapsulate its child components, so you can't just get the element by class as you would in a regular DOM.

Instead, I had to first access the shadowRoot, then look for the right <div> inside. For example, I was able to use this on https://modelviewer.dev/, it focuses the .userInput div whenever you click anywhere on the outer document. It uses some selection trickery that you might need to modify for your own use case:

window.addEventListener("click", (evt) => {
    console.log("Focusing...");
    document.getElementsByTagName("model-viewer")[0].shadowRoot.children[1].getElementsByClassName("userInput")[0].focus();
});

I presume since you have full control of your <model-viewer>, you might be able to use this focusing approach on the load event.

Update:

I just read that you want to give it keyboard focus upon clicking to dismiss the poster, so you might be able to use that "click" event instead of the load event.

  • Related