diff --git a/platform/javascript/godot_js.h b/platform/javascript/godot_js.h
index 19f3566af89..3e0e747b264 100644
--- a/platform/javascript/godot_js.h
+++ b/platform/javascript/godot_js.h
@@ -81,6 +81,8 @@ extern void godot_js_display_cursor_set_shape(const char *p_cursor);
 extern int godot_js_display_cursor_is_hidden();
 extern void godot_js_display_cursor_set_custom_shape(const char *p_shape, const uint8_t *p_ptr, int p_len, int p_hotspot_x, int p_hotspot_y);
 extern void godot_js_display_cursor_set_visible(int p_visible);
+extern void godot_js_display_cursor_lock_set(int p_lock);
+extern int godot_js_display_cursor_is_locked();
 
 // Display gamepad
 extern void godot_js_display_gamepad_cb(void (*p_on_change)(int p_index, int p_connected, const char *p_id, const char *p_guid));
diff --git a/platform/javascript/js/libs/library_godot_display.js b/platform/javascript/js/libs/library_godot_display.js
index a254c92d4d7..fa129f0e56a 100644
--- a/platform/javascript/js/libs/library_godot_display.js
+++ b/platform/javascript/js/libs/library_godot_display.js
@@ -376,6 +376,20 @@ const GodotDisplayCursor = {
 				delete GodotDisplayCursor.cursors[key];
 			});
 		},
+		lockPointer: function () {
+			const canvas = GodotConfig.canvas;
+			if (canvas.requestPointerLock) {
+				canvas.requestPointerLock();
+			}
+		},
+		releasePointer: function () {
+			if (document.exitPointerLock) {
+				document.exitPointerLock();
+			}
+		},
+		isPointerLocked: function () {
+			return document.pointerLockElement === GodotConfig.canvas;
+		},
 	},
 };
 mergeInto(LibraryManager.library, GodotDisplayCursor);
@@ -850,6 +864,20 @@ const GodotDisplay = {
 		}
 	},
 
+	godot_js_display_cursor_lock_set__sig: 'vi',
+	godot_js_display_cursor_lock_set: function (p_lock) {
+		if (p_lock) {
+			GodotDisplayCursor.lockPointer();
+		} else {
+			GodotDisplayCursor.releasePointer();
+		}
+	},
+
+	godot_js_display_cursor_is_locked__sig: 'i',
+	godot_js_display_cursor_is_locked: function () {
+		return GodotDisplayCursor.isPointerLocked() ? 1 : 0;
+	},
+
 	/*
 	 * Listeners
 	 */
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 55a751cb3de..031fed73916 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -493,27 +493,26 @@ void OS_JavaScript::set_mouse_mode(OS::MouseMode p_mode) {
 
 	if (p_mode == MOUSE_MODE_VISIBLE) {
 		godot_js_display_cursor_set_visible(1);
-		emscripten_exit_pointerlock();
+		godot_js_display_cursor_lock_set(false);
 
 	} else if (p_mode == MOUSE_MODE_HIDDEN) {
 		godot_js_display_cursor_set_visible(0);
-		emscripten_exit_pointerlock();
+		godot_js_display_cursor_lock_set(false);
 
 	} else if (p_mode == MOUSE_MODE_CAPTURED) {
 		godot_js_display_cursor_set_visible(1);
-		EMSCRIPTEN_RESULT result = emscripten_request_pointerlock(canvas_id, false);
-		ERR_FAIL_COND_MSG(result == EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED, "MOUSE_MODE_CAPTURED can only be entered from within an appropriate input callback.");
-		ERR_FAIL_COND_MSG(result != EMSCRIPTEN_RESULT_SUCCESS, "MOUSE_MODE_CAPTURED can only be entered from within an appropriate input callback.");
+		godot_js_display_cursor_lock_set(true);
 	}
 }
 
 OS::MouseMode OS_JavaScript::get_mouse_mode() const {
-	if (godot_js_display_cursor_is_hidden())
+	if (godot_js_display_cursor_is_hidden()) {
 		return MOUSE_MODE_HIDDEN;
-
-	EmscriptenPointerlockChangeEvent ev;
-	emscripten_get_pointerlock_status(&ev);
-	return (ev.isActive && String::utf8(ev.id) == String::utf8(&canvas_id[1])) ? MOUSE_MODE_CAPTURED : MOUSE_MODE_VISIBLE;
+	}
+	if (godot_js_display_cursor_is_locked()) {
+		return MOUSE_MODE_CAPTURED;
+	}
+	return MOUSE_MODE_VISIBLE;
 }
 
 // Wheel