Skip to main content

Speech to Text in Oracle APEX

Oracle APEX Tutorial

Speech to Text in
Oracle APEX

Oracle APEX JavaScript Web Speech API Voice Input Accessibility

I was working on an Oracle APEX application where users had to fill in a long notes field. Typing everything manually was getting annoying, especially on tablets. So I thought, why not add a voice input button that converts what the user says into text and puts it directly into the field?

Turns out, the browser already has this built in through something called the Web Speech API. No external libraries, no subscriptions, nothing to install. This post covers exactly how I got it working inside Oracle APEX using only a Static HTML Region and a small JavaScript block.

💡

This approach uses the browser's native Web Speech API, which works in Chrome and Edge. Firefox does not support it by default, and Safari has partial support.


The final result is a small voice input widget that sits next to any APEX text field. Here is a quick preview of what it looks like:

Live Preview
English (India)
🎤 Listening...
  • A microphone button that starts voice recognition on click
  • A language dropdown to switch between English US, India, or UK
  • A "Listening..." indicator so the user knows it is recording
  • The transcript gets appended directly into an APEX page item

I first tried using a third party JavaScript library to handle speech recognition. It had good docs but it was pulling in way too many dependencies and did not integrate cleanly with APEX's dynamic actions. The page started throwing errors because of APEX's own jQuery version conflicts.

⚠️

I tried external speech recognition libraries but it didn't work: loading an external speech library via APEX's JavaScript File URLs caused script loading order issues and multiple jQuery conflict errors in the browser console.

Then I came across the browser native window.SpeechRecognition API. No external files needed. It is already in Chrome. I just had to wrap it in a try-catch and attach it to a button click. That worked right away on the first test.

Finally this approach worked: using the browser's built-in Web Speech API directly inside Execute when Page Loads, with no extra dependencies at all.

One issue I faced was that the text was replacing what was already in the notes field instead of adding to it. Took me a while to figure out I needed to read the existing value using $v("P15_NOTES") first and then concatenate the new transcript before saving with $s().


01

Create a Static HTML Region

In your APEX page, add a new region and set its type to Static Content. This is where the microphone button and language selector will live.

02

Paste the HTML Markup

Add the microphone button, language select dropdown, and the status div into the region's HTML Content source area.

03

Add JavaScript on Page Load

Go to Page Properties and paste the recognition logic inside the Execute when Page Loads section. No dynamic action needed.

04

Add the CSS Styles

Paste the CSS into the page's Inline CSS section or into the theme roller. This styles the button, dropdown, and status messages.


This is the HTML markup that goes inside the Static Content region. It creates the microphone button, the language selector and the status messages.

HTML
<button type="button" id="start-speech" class="t-Button t-Button--noLabel" title="Start Voice Input">
  <span class="fa fa-microphone"></span>
</button>

<select id="speech-lang" class="t-Form-select">
  <option value="en-US">English (US)</option>
  <option value="en-IN">English (India)</option>
  <option value="en-GB">English (UK)</option>
</select>

<div id="listening-msg" style="display:none;">
  🎤 Listening...
</div>

<div id="speech-status" style="display:none;">
  <span class="fa fa-spinner fa-spin"></span> Voice recognition in progress...
</div>

Paste this inside the page's Execute when Page Loads section. This attaches the speech recognition logic to the microphone button.

JavaScript
document.getElementById("start-speech").addEventListener("click", function () {
  try {
    const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
    if (!SpeechRecognition) {
      alert("Speech Recognition is not supported in this browser.");
      return;
    }
    const recognition = new SpeechRecognition();
    const langSelect = document.getElementById("speech-lang");
    recognition.lang = langSelect.value;
    recognition.interimResults = false;
    recognition.maxAlternatives = 1;
    document.getElementById("speech-status").style.display = "block";
    document.getElementById("listening-msg").style.display = "block";
    recognition.start();
    recognition.onresult = function (event) {
      const speechResult = event.results[0][0].transcript;
      const currentText = $v("P15_NOTES");
      $s("P15_NOTES", currentText + " " + speechResult);
    };
    recognition.onerror = function (event) {
      console.error("Speech recognition error", event.error);
      alert("Error during speech recognition: " + event.error);
    };
    recognition.onend = function () {
      document.getElementById("speech-status").style.display = "none";
      document.getElementById("listening-msg").style.display = "none";
    };
  } catch (e) {
    console.error("Speech recognition not supported", e);
  }
});
🔑

The key part here is reading the existing text with $v("P15_NOTES") before calling $s() to save. Without this, every new transcript would overwrite what was already typed.

Add this to the Inline CSS section of your page. It styles the microphone button, the language dropdown, and the status messages so they fit nicely with the Universal Theme.

CSS
#speech-lang {
  padding: 6px 10px;
  border-radius: 8px;
  border: 1px solid #ccc;
  font-size: 14px;
  margin-top: 8px;
  margin-left: 8px;
}

#start-speech {
  background-color: #f0f4f7;
  border: 1px solid #ccc;
  border-radius: 50%;
  padding: 10px 12px;
  margin-right: 8px;
  cursor: pointer;
  transition: background-color 0.3s ease;
}

#start-speech:hover {
  background-color: #d0eaff;
}

#listening-msg {
  color: #0076d7;
  font-weight: bold;
  font-size: 14px;
  margin-top: 8px;
  display: flex;
  align-items: center;
  gap: 5px;
}

#speech-status {
  font-size: 13px;
  color: #555;
  margin-top: 4px;
  display: flex;
  align-items: center;
  gap: 6px;
}

🌐

One issue I faced: the Web Speech API only works on HTTPS pages. If your APEX application is running on plain HTTP during development, the microphone permission dialog will never appear. Make sure you are on a secure connection.

Also, changing P15_NOTES to whatever your actual page item name is. That is the only thing you need to update if you are using a different page item.

If you want to support more languages, just add more <option> tags to the select with the correct BCP 47 language codes like hi-IN for Hindi or ta-IN for Tamil.

🔄

The recognition fires once per button click. If you want continuous listening, set recognition.continuous = true and handle the stop logic manually with a toggle button.


That is pretty much all there is to it. No plugins, no paid services. The whole thing runs entirely in the browser. If you are building an APEX app where users need to fill in long text fields, this is a really simple way to make the experience a lot better, especially on mobile or tablet.

The live demo link below shows exactly how it looks when running in a real APEX environment. The GitHub link has all the code in one place if you want to clone it.

Comments

Popular posts from this blog

Screen Recorder in Oracle APEX (Single Page)

Oracle APEX Tutorial Screen Recorder in Oracle APEX : Single Page Build a fully functional browser-based screen recorder inside Oracle APEX using just one Static Content region and native JavaScript. No plugins, no external libraries, no server uploads required. ✍️ Why I Built This I was working on a client project where the support team needed to record screen issues and share them directly from the APEX application, without switching to any external tool. Installing third-party software was not an option on their machines, and every screen recorder extension required IT approval. That is when I thought: the browser already has everything we need. Why not build it right inside APEX? That idea turned into this. &#127916; Start / Stop Recording &#128065; Instant Preview ⬇️ One-click Download &#128266; Audio + Video ...

Sticky Notes Widget Inside Oracle APEX

Oracle APEX Project Building a Sticky Notes Widget in Oracle APEX How I built a fully draggable, color-coded, per-user sticky notes board using jQuery UI, APEX Ajax callbacks, and a bit of patience. Live Demo GitHub Repo Oracle APEX jQuery UI PL/SQL Ajax Callbacks JavaScript CSS Introduction Why I Built This I have been building internal tools on Oracle APEX for a while now, and one thing I always felt was missing was a place where users could quickly jot down thoughts without leaving the page. Think of it like a personal scratchpad that lives right inside the app. I had seen sticky note UIs in some Google products and I thought, how hard can this be in APEX? It turned out to be more interesting than I expected. There were a few wrong tu...

IG Drag Fill Series

Excel Drag Fill in Oracle APEX Interactive Grid Oracle APEX · Interactive Grid Excel-Like Drag & Fill in APEX IG "I spent way too long trying to get this working… and then one weird jQuery trick changed everything." Oracle APEX Interactive Grid jQuery JavaScript PL/SQL CSS Live Demo GitHub scroll The Backstory If you've used Excel for even ten minutes, you already know that little green handle at the corner of a selected cell. You drag it down, and boom, values fill across every row automatically. It's one of those features users love so much they don't even think about it. They just expect it everywhere. So when a ...