javascriptioskeyboardspeech-to-textdictation

Stop dictation on iOS using JavaScript


I'm working on a chat app and I'm facing a weird problem with the dictation feature on iOS.

Here is the scenario:

Does anyone know how to tell iOS to stop the dictation (preferably using JavaScript but a solution in Swift would also help).

Thanks! Jesse

Minimal example:

const input = document.getElementById('input');
const button = document.getElementById('button');
button.addEventListener('click', () => {
  input.value = '';
  input.focus();
})
<input id="input"/>
<button id="button">Send</button>

<ul>
  <li>Open this page on iOS</li>
  <li>Focus the input and start dication</li>
  <li>Click send => input is cleared</li>
  <li>Click on the input => text is entered again :(</li>
</ul>

https://codepen.io/jjd/pen/vYZMGBy


Solution

  • I had the same situation recently and managed to replicate it on some chat demos around the web with the same issue, and after digging up for a while, I found old answers as well as explanations to why that occurs (and why some solutions fails).

    The key here is that the iOS dictation ends when:

    1. User lose focus of the input (taps elsewhere).
    2. User taps on the Done button of the iOS keyboard.

    While in theory tapping your Send button should remove the focus from the chat input and finish the dictation, in practice the sequence between losing input focus and reverting it is so quick that iOS doesn't bother to finish the dictation, as it recovers the focus right away anyways. And plus, adding some delay to allow the iOS keyboard to finish will end up hiding the keyboard, which could end up closing and opening many times as you send messages and handle the focus manually, which is not desirable.

    If you look here, you can see a quick explanation of the subject, with a possible solution for your problem, I tested most solutions in that thread and they still works as for iOS 14. The idea that worked for me is to remove the focus on an element and focus on a similar element to avoid hiding the keyboard, and then revert it back manually, with the difference that it must be asynchronous to guarantee a proper response from iOS. The way I did it was to create a dummy text input and redirect the focus to that:

    const dummy = document.createElement('input');
          dummy.setAttribute('type', 'text');
          dummy.style.position = 'absolute';
          dummy.style.opacity = 0;
          dummy.style.height = 0;
          document.body.append(dummy);
          dummy.focus();
    

    Then, set an async timeout to redirect to the real input element, clear input, etc:

    setTimeout(() => {
        input.value = '';
        input.focus();
        dummy.remove(); //Notice this
    }, 100);
    

    Is hacky, but it gets the job done. I have no idea how other websites/applications handle this situation, as I only tested native applications instead of websites. Perhaps their clean code doesn't have this issue in the first place? 😛