diff --git a/examples/javascript_interop/index.html b/examples/javascript_interop/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..cad532cd62a586ec88ad0b21ca6bcf14066a196a
--- /dev/null
+++ b/examples/javascript_interop/index.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <title>JavaScript Interop</title>
+
+    <script src="../testapp/testapp.js"></script>
+    <script src="../testapp/qtloader.js"></script>
+    <script>
+
+        // JavaScript function which can be called from C++, see
+        // ../testapp/jsinterop.cpp
+        function helloJs(name) {
+            console.log("Hello " + name + " from helloJs");
+        }
+
+        // A pice of data, can be accessed from C++ as well
+        window.data = new Uint8Array([1, 2, 3 ,4]);
+
+        window.addEventListener('load', async () => {
+            const instance = await qtLoad({qt:{}});
+
+            // enable the "Call C++" button which calls the function exported from jsinterop.cpp.
+            const callCppButton = document.getElementById("callcpp");
+            callCppButton.disabled = false;
+            callCppButton.addEventListener("click", () => {
+                instance["helloCpp"]("Qt");
+            });
+        })
+    </script>
+  </head>
+  <body>
+      <h1>Qt for WebAssembly: JavaScript Interop</h1>
+      <p> This examples show how to call C++ functions from JavaScript,
+          and vice versa. Output is printed to the JavaScript console.</p>
+      <button type="button" id="callcpp" disabled>Call C++ function</button>
+  </body>
+</html>
diff --git a/examples/javascript_interop/testapp.wasm b/examples/javascript_interop/testapp.wasm
new file mode 120000
index 0000000000000000000000000000000000000000..25fc4bc6bd46bc4fe8609614372a9da05bb8607f
--- /dev/null
+++ b/examples/javascript_interop/testapp.wasm
@@ -0,0 +1 @@
+../testapp/testapp.wasm
\ No newline at end of file
diff --git a/examples/testapp/CMakeLists.txt b/examples/testapp/CMakeLists.txt
index 2e6fb896dbaabab97c60d2b0a2468a2e393fcdb5..35ff3d2e579db7580f0ad7901e1dc7117620b74a 100644
--- a/examples/testapp/CMakeLists.txt
+++ b/examples/testapp/CMakeLists.txt
@@ -6,7 +6,11 @@ set(CMAKE_AUTOMOC ON)
 find_package(Qt6 REQUIRED COMPONENTS Core Gui)
 
 qt_add_executable(testapp
-    main.cpp rasterwindow.cpp ../../qtwebutils.cpp popup.cpp
+    main.cpp
+    rasterwindow.cpp
+    popup.cpp
+    jsinterop.cpp
+    ../../qtwebutils.cpp
 )
 
 target_link_libraries(testapp PUBLIC
diff --git a/examples/testapp/jsinterop.cpp b/examples/testapp/jsinterop.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..49a851ccdf0933e9b39bdc54c408263bd51efda8
--- /dev/null
+++ b/examples/testapp/jsinterop.cpp
@@ -0,0 +1,36 @@
+#include <QtCore>
+#include <algorithm>
+#include <emscripten/bind.h>
+#include <emscripten/val.h>
+
+// This example demonstrates how to interop with JavaScript code
+// and data from C++ using Emscripten bind.h and val.h.
+
+// Sample C++ function. This function is exported to JavaScript using
+// EMSCRIPTEN_BINDINGS below.
+void helloCpp(std::string name)
+{
+    qDebug() << "Hello" << QString::fromStdString(name) << "from helloCpp";
+
+    // Call JS function. See defenition in ../examples/jsinterop/jsinterop.cpp
+    // The function is accessed via the global "window" object.
+    emscripten::val window = emscripten::val::global("window");
+    window.call<void>("helloJs", name);
+
+    // Copy data from a JavaScript Array. This copies from the
+    // JavaScript heap to the C++ heap.
+    QByteArray data = QByteArray::fromEcmaUint8Array(window["data"]);
+    qDebug() << "Got data bytes" << QString::number(data[0]) << QString::number(data[1])
+                                 << QString::number(data[2]) << QString::number(data[3]);
+
+    // Clear Js-side data, if we don't want to hold a copy there
+    window.set("data", emscripten::val::null());
+    
+    // Or assign back to it
+    std::reverse(data.begin(), data.end());
+    window.set("data", data.toEcmaUint8Array());
+}
+
+EMSCRIPTEN_BINDINGS(qt_webutils) {
+    emscripten::function("helloCpp", &helloCpp);
+}