diff --git a/enterprise/frontend/src/embedding-sdk/lib/polyfill-use-sync-external-store.ts b/enterprise/frontend/src/embedding-sdk/lib/polyfill-use-sync-external-store.ts
index 8a6996db8f743eb0648b34c7fc9b8ccbcb19442c..c4053599a9d8cec2c85d620ab3cb9f953b6f093c 100644
--- a/enterprise/frontend/src/embedding-sdk/lib/polyfill-use-sync-external-store.ts
+++ b/enterprise/frontend/src/embedding-sdk/lib/polyfill-use-sync-external-store.ts
@@ -1,11 +1,11 @@
 import React from "react";
 import { useSyncExternalStore } from "use-sync-external-store/shim";
 
-import { isReact17OrEarlier } from "metabase/lib/react-compat";
-
 // Monkey-patches useSyncExternalStore if we are in React 17,
 // where useSyncExternalStore is not available.
 // This is used in react-redux v8, until they've dropped the shim in v9.
-if (isReact17OrEarlier()) {
+export const shouldShimExternalStore = () => !("useSyncExternalStore" in React);
+
+if (shouldShimExternalStore()) {
   React.useSyncExternalStore = useSyncExternalStore;
 }
diff --git a/frontend/src/metabase/lib/compat/check-version.ts b/frontend/src/metabase/lib/compat/check-version.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7196128312f36fc069a5345da2cbd338836cb845
--- /dev/null
+++ b/frontend/src/metabase/lib/compat/check-version.ts
@@ -0,0 +1,7 @@
+import React from "react";
+
+export const getMajorReactVersion = () => {
+  const versionParts = React.version.split(".").map(Number);
+
+  return versionParts[0];
+};
diff --git a/frontend/src/metabase/lib/compat/check-version.unit.spec.ts b/frontend/src/metabase/lib/compat/check-version.unit.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1197d4ceddf798352d1a38eb91c7b1dedff42aed
--- /dev/null
+++ b/frontend/src/metabase/lib/compat/check-version.unit.spec.ts
@@ -0,0 +1,41 @@
+import React from "react";
+
+import { getMajorReactVersion } from "./check-version";
+
+describe("getMajorReactVersion", () => {
+  const versions = [
+    { version: "0.14.0", expected: 0 },
+    { version: "15.0.0", expected: 15 },
+    { version: "16.0.0", expected: 16 },
+    { version: "16.8.0", expected: 16 },
+    { version: "17.0.0", expected: 17 },
+    { version: "17.0.2", expected: 17 },
+    { version: "18.0.0", expected: 18 },
+    { version: "18.1.0", expected: 18 },
+  ];
+
+  beforeEach(() => {
+    jest.resetModules();
+  });
+
+  it.each(versions)(
+    "should return $expected for React version $version",
+    ({ version, expected }) => {
+      Object.defineProperty(React, "version", {
+        value: version,
+        writable: true,
+      });
+
+      expect(getMajorReactVersion()).toBe(expected);
+    },
+  );
+
+  it("should return NaN for an invalid version string", () => {
+    Object.defineProperty(React, "version", {
+      value: "invalid-version",
+      writable: true,
+    });
+
+    expect(getMajorReactVersion()).toBeNaN();
+  });
+});
diff --git a/frontend/src/metabase/lib/react-compat.ts b/frontend/src/metabase/lib/react-compat.ts
index d51c748b1ef0e381146787cc05a7b861fb222368..01a43a1c58eeade8d2e76be13c9225ae14a2000b 100644
--- a/frontend/src/metabase/lib/react-compat.ts
+++ b/frontend/src/metabase/lib/react-compat.ts
@@ -1,17 +1,17 @@
 // Support React 17 backwards compatibility for the Embedding SDK
-
-import React from "react";
+import type React from "react";
 import ReactDOM from "react-dom";
 import { type Root, createRoot } from "react-dom/client";
 
-// React 18 and later has the useSyncExternalStore hook.
-export const isReact17OrEarlier = () => !("useSyncExternalStore" in React);
+import { getMajorReactVersion } from "./compat/check-version";
 
 export function renderRoot(
   content: React.JSX.Element,
   element: Element,
 ): Root | undefined {
-  if (isReact17OrEarlier()) {
+  const reactVersion = getMajorReactVersion();
+
+  if (reactVersion <= 17) {
     ReactDOM.render(content, element);
     return;
   }
@@ -23,7 +23,9 @@ export function renderRoot(
 }
 
 export function unmountRoot(root?: Root, element?: Element) {
-  if (isReact17OrEarlier() && element) {
+  const reactVersion = getMajorReactVersion();
+
+  if (reactVersion <= 17 && element) {
     ReactDOM.unmountComponentAtNode(element);
     return;
   }
diff --git a/frontend/src/metabase/visualizations/components/TableInteractive/TableInteractive.jsx b/frontend/src/metabase/visualizations/components/TableInteractive/TableInteractive.jsx
index b090fb53d9fd93f41d0d02b3ac8b305157a84c0d..83f6e4e6a01cb9f6363388772d0dfd165ce0677f 100644
--- a/frontend/src/metabase/visualizations/components/TableInteractive/TableInteractive.jsx
+++ b/frontend/src/metabase/visualizations/components/TableInteractive/TableInteractive.jsx
@@ -2,7 +2,6 @@
 import cx from "classnames";
 import PropTypes from "prop-types";
 import { Component, createRef, forwardRef } from "react";
-import { findDOMNode } from "react-dom";
 import { connect } from "react-redux";
 import { Grid, ScrollSync } from "react-virtualized";
 import { t } from "ttag";
@@ -115,6 +114,8 @@ class TableInteractive extends Component {
     this.headerRefs = [];
     this.detailShortcutRef = createRef();
 
+    this.gridRef = createRef();
+
     window.METABASE_TABLE = this;
   }
 
@@ -1042,7 +1043,7 @@ class TableInteractive extends Component {
       return;
     }
 
-    const scrollOffset = findDOMNode(this.grid)?.scrollTop || 0;
+    const scrollOffset = this.gridRef.current?.scrollTop || 0;
 
     // infer row index from mouse position when we hover the gutter column
     if (event?.currentTarget?.id === "gutter-column") {
@@ -1309,7 +1310,7 @@ class TableInteractive extends Component {
   }
 
   _benchmark() {
-    const grid = findDOMNode(this.grid);
+    const grid = this.gridRef.current;
     const height = grid.scrollHeight;
     let top = 0;
     let start = Date.now();