reactjsnext.jsplayback

How to press a key to play a sound on React


My work frame: Next.JS v13.4.19

What I am doing: Trying to play soundbites when I press a certain key.

How I am doing it: The function handlePlay() look for certain key press and triggers the play() function for a specific soundbite when it matches.

So far my function works just fine. If I press Q, S or D, it will play the file I want.

My problem: it works only if I click one of the buttons first.

My goal: to play these soundbites from the keyboard as soon as the page has loaded.

My code

"use client"

export default function Home() {
  
  function handlePlay(e) {
    if (e.keyCode === 81) {
      kick.play()
    } else if (e.keyCode === 83) {
      hat.play()
    } else if (e.keyCode === 68) {
      snare.play()
    }
  };


  return (
    <div onKeyDown={(e) => handlePlay(e)}>
      <audio id="kick" src="kick.wav"></audio>
      <audio id="hat" src="hat.wav"></audio>
      <audio id="snare" src="snare.wav"></audio>

      <button onClick={() => kick.play()}>
        Kick
      </button>
      <button onClick={() => hat.play()}>
        Hat
      </button>
      <button onClick={() => snare.play()}>
        Snare
      </button>
    </div>
  )
}

Solution

  • The issue is your div wont capture keyup events unless you're actively pressing keys while the element (Or a child of the element) is focused. Try a useEffect hook that attaches the listener to the document instead of a specific div:

    "use client"
    
    export default function Home() {
      useEffect(() => {
        document.addEventListener('keydown', handlePlay)
    
        return () => document.removeEventListener('keydown', handlePlay)
      }, [])
      
      function handlePlay(e) {
        if (e.keyCode === 81) {
          kick.play()
        } else if (e.keyCode === 83) {
          hat.play()
        } else if (e.keyCode === 68) {
          snare.play()
        }
      };
    
    
      return (
        <div>
          <audio id="kick" src="kick.wav"></audio>
          <audio id="hat" src="hat.wav"></audio>
          <audio id="snare" src="snare.wav"></audio>
    
          <button onClick={() => kick.play()}>
            Kick
          </button>
          <button onClick={() => hat.play()}>
            Hat
          </button>
          <button onClick={() => snare.play()}>
            Snare
          </button>
        </div>
      )
    }