diff --git a/ui/global.d.ts b/ui/global.d.ts
index 331f91ce60746f0728ad5e5272f1e2300cb82505..8f1746972f12e8ff204b6bac8d4def27f0758a5c 100644
--- a/ui/global.d.ts
+++ b/ui/global.d.ts
@@ -1,36 +1,9 @@
-import type { PropsValues } from '@/types/Form';
 import type React from 'react';
 import type ReactDom from 'react-dom';
 // eslint-disable-next-line @typescript-eslint/no-restricted-imports
 import type * as ReactRedux from 'react-redux';
 import type * as ReduxToolkit from '@reduxjs/toolkit';
-
-interface DrupalSettings {
-  xb: {
-    base: string;
-    entityType: string;
-    entity: string;
-    entityTypeKeys: {
-      id: string;
-      label: string;
-    };
-    globalAssets: {
-      css: string;
-      jsHeader: string;
-      jsFooter: string;
-    };
-    layoutUtils: PropsValues;
-    componentSelectionUtils: PropsValues;
-    navUtils: PropsValues;
-    xbModulePath: string;
-    selectedComponent: string;
-    devMode: boolean;
-  };
-  xbExtension: object;
-  path: {
-    baseUrl: string;
-  };
-}
+import type { DrupalSettings } from '@/types/DrupalSettings';
 
 interface CKEditor5Types {
   editorClassic: {
diff --git a/ui/src/components/ComponentPreview.tsx b/ui/src/components/ComponentPreview.tsx
index 9c3d6cc36758ea846b9197cf0bed5f4a6974d1c3..21ffccbefdf1377afcfc51a39489b1d705d35c08 100644
--- a/ui/src/components/ComponentPreview.tsx
+++ b/ui/src/components/ComponentPreview.tsx
@@ -4,12 +4,14 @@ import styles from './ComponentPreview.module.css';
 import clsx from 'clsx';
 import type { XBComponent } from '@/types/Component';
 import type { Section } from '@/types/Section';
+import { getBaseUrl, getDrupalSettings } from '@/utils/drupal-globals';
 
 interface ComponentPreviewProps {
   componentListItem: XBComponent | Section;
 }
 
-const { drupalSettings } = window;
+const drupalSettings = getDrupalSettings();
+const baseUrl = getBaseUrl();
 
 const ComponentPreview: React.FC<ComponentPreviewProps> = ({
   componentListItem,
@@ -27,7 +29,7 @@ const ComponentPreview: React.FC<ComponentPreviewProps> = ({
     drupalSettings?.xb.globalAssets.jsHeader + component.js_header;
 
   const markup = component.default_markup;
-  const base_url = window.location.origin + drupalSettings?.path.baseUrl;
+  const base_url = window.location.origin + baseUrl;
 
   const html = `
 <html>
diff --git a/ui/src/components/extensions/ExtensionsList.tsx b/ui/src/components/extensions/ExtensionsList.tsx
index 6ca53731e863dfd9be48316a8ee1083573351d16..6e665a763e716c6f2c3233738f5f06c52140441c 100644
--- a/ui/src/components/extensions/ExtensionsList.tsx
+++ b/ui/src/components/extensions/ExtensionsList.tsx
@@ -3,10 +3,17 @@ import { ExternalLinkIcon } from '@radix-ui/react-icons';
 import ExtensionButton from '@/components/extensions/ExtensionButton';
 import { handleNonWorkingBtn } from '@/utils/function-utils';
 import type React from 'react';
+import {
+  getBaseUrl,
+  getDrupalSettings,
+  getXbSettings,
+} from '@/utils/drupal-globals';
 
 interface ExtensionsPopoverProps {}
 
-const { drupalSettings } = window;
+const drupalSettings = getDrupalSettings();
+const baseUrl = getBaseUrl();
+const xbSettings = getXbSettings();
 
 const ExtensionsList: React.FC<ExtensionsPopoverProps> = () => {
   let extensionsList = [];
@@ -16,7 +23,7 @@ const ExtensionsList: React.FC<ExtensionsPopoverProps> = () => {
         ...value,
         imgSrc:
           value.imgSrc ||
-          `${drupalSettings.path.baseUrl}${drupalSettings.xb.xbModulePath}/ui/assets/icons/extension-default-abstract.svg`,
+          `${baseUrl}${xbSettings.xbModulePath}/ui/assets/icons/extension-default-abstract.svg`,
         name: value.name,
         description: value.description,
       };
diff --git a/ui/src/components/form/components/drupal/DrupalTextArea.tsx b/ui/src/components/form/components/drupal/DrupalTextArea.tsx
index 2a6b49cb197c182487298946d741b4ea0674ff44..9b02c611828d6400e9ebb892d00910986aed91bd 100644
--- a/ui/src/components/form/components/drupal/DrupalTextArea.tsx
+++ b/ui/src/components/form/components/drupal/DrupalTextArea.tsx
@@ -5,7 +5,9 @@ import { useRef, useState } from 'react';
 import { Flex } from '@radix-ui/themes';
 import type { Attributes } from '@/types/DrupalAttribute';
 import DrupalFormattedTextArea from './DrupalFormattedTextArea';
-const { drupalSettings } = window as any;
+import { getDrupalSettings } from '@/utils/drupal-globals';
+import type { FormatType } from '@/types/FormatType';
+const drupalSettings = getDrupalSettings();
 
 const DrupalTextArea = ({
   attributes = {},
@@ -67,20 +69,6 @@ const DrupalTextArea = ({
   );
 };
 
-interface FormatType {
-  format: string;
-  editor?: string;
-  editorSettings?: {
-    toolbar: any[];
-    plugins: string[];
-    config: {
-      [key: string]: any;
-    };
-    language: Record<string, any>;
-  };
-  [key: string]: any;
-}
-
 interface FormatSelectProps {
   attributes: Attributes;
   selectAttributes: Record<string, any>;
diff --git a/ui/src/components/form/formUtil.ts b/ui/src/components/form/formUtil.ts
index fbc40cdd079a537e7a88a9f772f8b92207a55fde..a1f6ce1958d0d13536392ccf540af46bc7b1012d 100644
--- a/ui/src/components/form/formUtil.ts
+++ b/ui/src/components/form/formUtil.ts
@@ -14,6 +14,7 @@ import type { TransformConfig, Transforms } from '@/utils/transforms';
 import transforms from '@/utils/transforms';
 import qs from 'qs';
 import addDraft2019 from 'ajv-formats-draft2019';
+import { getDrupal } from '@/utils/drupal-globals';
 const ajv = new Ajv();
 addFormats(ajv);
 addDraft2019(ajv);
@@ -338,7 +339,7 @@ export function getPropsValues(
   // Iterate through every item in form state that corresponds to
   // a component input to create propsValues, which will ultimately be
   // used to update this component's model.
-  const { Drupal } = (window as any) || {
+  const Drupal = getDrupal() || {
     Drupal: { xbTransforms: transforms },
   };
   const transformsList: Transforms = Drupal?.xbTransforms || transforms;
diff --git a/ui/src/components/pageInfo/PageInfo.tsx b/ui/src/components/pageInfo/PageInfo.tsx
index dbd92beef0390e4afdedbd705d9afddb2507f5b5..cf206b314f2e16223a8f7f5d50a3b69658258965 100644
--- a/ui/src/components/pageInfo/PageInfo.tsx
+++ b/ui/src/components/pageInfo/PageInfo.tsx
@@ -40,7 +40,7 @@ import {
   selectEntityId,
   selectEntityType,
 } from '@/features/configuration/configurationSlice';
-import { getBaseUrl } from '@/utils/drupal-globals';
+import { getBaseUrl, getXbSettings } from '@/utils/drupal-globals';
 
 interface PageType {
   [key: string]: ReactElement;
@@ -53,7 +53,7 @@ const iconMap: PageType = {
   GlobalSectionName: <SectionIcon />,
 };
 
-const { drupalSettings } = window;
+const xbSettings = getXbSettings();
 
 const PageInfo = () => {
   const { showBoundary } = useErrorBoundary();
@@ -68,7 +68,7 @@ const PageInfo = () => {
   )?.name;
   const entity_form_fields = useAppSelector(selectPageData);
   const title =
-    entity_form_fields[`${drupalSettings.xb.entityTypeKeys.label}[0][value]`];
+    entity_form_fields[`${xbSettings.entityTypeKeys.label}[0][value]`];
 
   const {
     data: pageItems,
diff --git a/ui/src/components/topbar/Topbar.tsx b/ui/src/components/topbar/Topbar.tsx
index 9b928410c7f09c03c5a393e2807663fd826b419a..b3ea2282ecdb89e257ba6e93e313961fcf64433c 100644
--- a/ui/src/components/topbar/Topbar.tsx
+++ b/ui/src/components/topbar/Topbar.tsx
@@ -21,10 +21,11 @@ import ExtensionsList from '@/components/extensions/ExtensionsList';
 import TopbarPopover from '@/components/topbar/menu/TopbarPopover';
 import topBarStyles from '@/components/topbar/Topbar.module.css';
 import DynamicComponents from '@/components/dynamicComponents/DynamicComponents';
+import { getDrupalSettings } from '@/utils/drupal-globals';
 
 const PREVIOUS_URL_STORAGE_KEY = 'XBPreviousURL';
 
-const { drupalSettings } = window;
+const drupalSettings = getDrupalSettings();
 
 const Topbar = () => {
   const navigate = useNavigate();
diff --git a/ui/src/features/drupal/drupalUtil.ts b/ui/src/features/drupal/drupalUtil.ts
deleted file mode 100644
index 7a66dd17f6a6463197ad1cb79fe7a897a09be9a8..0000000000000000000000000000000000000000
--- a/ui/src/features/drupal/drupalUtil.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import type { PropsValues } from '@/types/Form';
-
-const { drupalSettings } = window;
-export const setXbDrupalSetting = (
-  property: 'layoutUtils' | 'navUtils',
-  value: PropsValues,
-) => {
-  if (drupalSettings?.xb?.[property]) {
-    drupalSettings.xb[property] = { ...drupalSettings.xb[property], ...value };
-  }
-};
diff --git a/ui/src/features/layout/layoutModelSlice.ts b/ui/src/features/layout/layoutModelSlice.ts
index a2e01b7b1c61b00b5e0c7672db79c2f2ff67dd78..dee6177f45c73d54808b52d5aee8ecf9ffcd2ffa 100644
--- a/ui/src/features/layout/layoutModelSlice.ts
+++ b/ui/src/features/layout/layoutModelSlice.ts
@@ -8,7 +8,7 @@ import { createSelector } from '@reduxjs/toolkit';
 import { createSlice } from '@reduxjs/toolkit';
 import type { StateWithHistory } from 'redux-undo';
 import { v4 as uuidv4 } from 'uuid';
-import { setXbDrupalSetting } from '@/features/drupal/drupalUtil';
+import { setXbDrupalSetting } from '@/utils/drupal-globals';
 import {
   findComponentByUuid,
   findNodePathByUuid,
diff --git a/ui/src/features/layout/layoutUtils.ts b/ui/src/features/layout/layoutUtils.ts
index 8c4b3baf6ebfac3dd36ec08f7b72a9ad72003267..fca9fd9e1c9011eebe9eb6a398489adbeeb33b72 100644
--- a/ui/src/features/layout/layoutUtils.ts
+++ b/ui/src/features/layout/layoutUtils.ts
@@ -8,7 +8,7 @@ import type {
 } from './layoutModelSlice';
 import { NodeType } from './layoutModelSlice';
 import { v4 as uuidv4 } from 'uuid';
-import { setXbDrupalSetting } from '@/features/drupal/drupalUtil';
+import { setXbDrupalSetting } from '@/utils/drupal-globals';
 import { isConsecutive } from '@/utils/function-utils';
 
 type NodeFunction = (
diff --git a/ui/src/features/layout/preview/Preview.tsx b/ui/src/features/layout/preview/Preview.tsx
index 6d23b26ce27635002e47bb589d6f16db6d443930..010011d9e4b5e42067f169d3f961918e233a744d 100644
--- a/ui/src/features/layout/preview/Preview.tsx
+++ b/ui/src/features/layout/preview/Preview.tsx
@@ -18,6 +18,7 @@ import { selectPageData } from '@/features/pageData/pageDataSlice';
 import { selectPreviewHtml } from '@/features/pagePreview/previewSlice';
 import { contentApi } from '@/services/content';
 import { selectSelectedComponentUuid } from '@/features/ui/uiSlice';
+import { getXbSettings } from '@/utils/drupal-globals';
 
 interface PreviewProps {}
 
@@ -33,9 +34,9 @@ const previewSizes = {
     name: 'Mobile',
   },
 };
-const { drupalSettings } = window;
+const xbSettings = getXbSettings();
 type PreviewSizeKey = keyof typeof previewSizes;
-const labelFormKey = `${drupalSettings.xb.entityTypeKeys.label}[0][value]`;
+const labelFormKey = `${xbSettings.entityTypeKeys.label}[0][value]`;
 
 const Preview: React.FC<PreviewProps> = () => {
   const layout = useAppSelector(selectLayout);
diff --git a/ui/src/hooks/useComponentSelection.ts b/ui/src/hooks/useComponentSelection.ts
index 2f0a20f2ca0c47d278e86684563bb428d203fa89..c2c35d1a8c6bff09338c52c6e3be2658ce2ceee9 100644
--- a/ui/src/hooks/useComponentSelection.ts
+++ b/ui/src/hooks/useComponentSelection.ts
@@ -17,8 +17,9 @@ import {
 import type { RegionNode } from '@/features/layout/layoutModelSlice';
 import { selectLayout } from '@/features/layout/layoutModelSlice';
 import { selectDevMode } from '@/features/configuration/configurationSlice';
+import { getXbSettings } from '@/utils/drupal-globals';
 
-const { drupalSettings } = window;
+const xbSettings = getXbSettings();
 
 /**
  * Filters out any components that are parents or children of components in the selection
@@ -263,7 +264,7 @@ export function useComponentSelection() {
   };
 
   // Add to Drupal settings for external access by extensions etc
-  drupalSettings.xb.componentSelectionUtils = componentSelectionUtils;
+  xbSettings.componentSelectionUtils = componentSelectionUtils;
 
   return componentSelectionUtils;
 }
diff --git a/ui/src/hooks/useDrupalBehaviors.ts b/ui/src/hooks/useDrupalBehaviors.ts
index 0b95f17b704a4bad50cd8e775786960f09deea20..a245db9f597143898f6be5f12553bda7323bc489 100644
--- a/ui/src/hooks/useDrupalBehaviors.ts
+++ b/ui/src/hooks/useDrupalBehaviors.ts
@@ -1,7 +1,8 @@
 import { useEffect } from 'react';
 import type { RefObject } from 'react';
+import { getDrupal } from '@/utils/drupal-globals';
 
-const { Drupal } = window as any;
+const Drupal = getDrupal();
 
 export function useDrupalBehaviors(
   ref: RefObject<HTMLElement>,
diff --git a/ui/src/hooks/useEditorNavigation.ts b/ui/src/hooks/useEditorNavigation.ts
index db468a93656c2c793e54a5b017161a836ce9fafa..e0ae3448af98c4bde1e173060ef4adf64cf57d72 100644
--- a/ui/src/hooks/useEditorNavigation.ts
+++ b/ui/src/hooks/useEditorNavigation.ts
@@ -1,9 +1,9 @@
 import { useCallback } from 'react';
 import { useNavigate } from 'react-router-dom';
 import { DEFAULT_REGION } from '@/features/ui/uiSlice';
-import { getBaseUrl } from '@/utils/drupal-globals';
+import { getBaseUrl, getXbSettings } from '@/utils/drupal-globals';
 
-const { drupalSettings } = window;
+const xbSettings = getXbSettings();
 
 /**
  * Hook for editor navigation functions
@@ -43,7 +43,7 @@ export function useEditorNavigation() {
     setEditorEntity,
   };
 
-  drupalSettings.xb.navUtils = editorNavUtils;
+  xbSettings.navUtils = editorNavUtils;
 
   return editorNavUtils;
 }
diff --git a/ui/src/main.tsx b/ui/src/main.tsx
index ce94c11ff98dcfe4255038d105cb5b17e1df6fa0..00d3fbc54edfd4148348e3899a4a15dc897cc1b0 100644
--- a/ui/src/main.tsx
+++ b/ui/src/main.tsx
@@ -20,6 +20,7 @@ import transforms from '@/utils/transforms';
 import '@/styles/radix-themes';
 import '@/styles/index.css';
 import { AJAX_UPDATE_FORM_STATE_EVENT } from '@/types/Ajax';
+import { getBaseUrl, getDrupal, getXbSettings } from '@/utils/drupal-globals';
 
 // Provide these dependencies as globals so extensions do not have redundant and
 // potentially conflicting dependencies.
@@ -32,17 +33,18 @@ interface ProviderComponentProps {
   store: EnhancedStore;
 }
 
-const { drupalSettings } = window;
-const { Drupal } = window as any;
+const Drupal = getDrupal();
+const xbSettings = getXbSettings();
+const baseUrl = getBaseUrl();
 
 const container = document.getElementById('experience-builder');
 
 const appConfiguration: AppConfiguration = {
   ...initialState,
-  baseUrl: drupalSettings?.path?.baseUrl || import.meta.env.BASE_URL,
-  entityType: drupalSettings?.xb?.entityType || 'node',
-  entity: drupalSettings?.xb?.entity || '1',
-  devMode: drupalSettings?.xb?.devMode || false,
+  baseUrl: baseUrl || import.meta.env.BASE_URL,
+  entityType: xbSettings.entityType || 'node',
+  entity: xbSettings.entity || '1',
+  devMode: xbSettings.devMode || false,
 };
 
 const isAjaxing = () =>
@@ -88,13 +90,13 @@ Drupal.attachBehaviorsAfterAjaxing = attachBehaviorsAfterAjaxing;
 if (container) {
   const root = createRoot(container);
   let routerRoot = appConfiguration.baseUrl;
-  if (drupalSettings?.xb?.base) {
-    routerRoot = `${routerRoot}${drupalSettings.xb.base}`;
+  if (xbSettings.base) {
+    routerRoot = `${routerRoot}${xbSettings.base}`;
   }
   const store = makeStore({ configuration: appConfiguration });
 
   // Make the store available to extensions.
-  (drupalSettings as any).xb.store = store;
+  xbSettings.store = store;
 
   root.render(
     <React.StrictMode>
diff --git a/ui/src/services/addAjaxPageState.ts b/ui/src/services/addAjaxPageState.ts
index 4f0af374877d79baedc58695c24f960e84b34ae2..fd082b8a3c7ba65213f7a157cbc15aaf9f02b107 100644
--- a/ui/src/services/addAjaxPageState.ts
+++ b/ui/src/services/addAjaxPageState.ts
@@ -1,4 +1,6 @@
-const { drupalSettings } = window as any;
+import { getDrupalSettings } from '@/utils/drupal-globals';
+
+const drupalSettings = getDrupalSettings();
 
 const addAjaxPageState = (query: string) => {
   // Drupal's AJAX API automatically adds ajaxPageState as a parameter, but
diff --git a/ui/src/services/processResponseAssets.ts b/ui/src/services/processResponseAssets.ts
index 3c9f54e8c5774a28b6edcdba5260b3c7863b16b4..c8c88430aa4488fa16832f203dcbdfdeee9c9e5c 100644
--- a/ui/src/services/processResponseAssets.ts
+++ b/ui/src/services/processResponseAssets.ts
@@ -1,6 +1,7 @@
 import type { PropsValues } from '@/types/Form';
+import { getDrupal } from '@/utils/drupal-globals';
 
-const { Drupal } = window as any;
+const Drupal = getDrupal();
 
 /**
  * Takes a response rendered by XBTemplateRenderer, identifies any attached
diff --git a/ui/src/types/DrupalSettings.ts b/ui/src/types/DrupalSettings.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f817332eccc1c40339c20148a342a9c8c2cd8900
--- /dev/null
+++ b/ui/src/types/DrupalSettings.ts
@@ -0,0 +1,39 @@
+import type { PropsValues } from '@/types/Form';
+import type { FormatType } from '@/types/FormatType';
+
+export interface DrupalSettings {
+  xb: {
+    base: string;
+    entityType: string;
+    entity: string;
+    entityTypeKeys: {
+      id: string;
+      label: string;
+    };
+    globalAssets: {
+      css: string;
+      jsHeader: string;
+      jsFooter: string;
+    };
+    layoutUtils: PropsValues;
+    componentSelectionUtils: PropsValues;
+    navUtils: PropsValues;
+    xbModulePath: string;
+    selectedComponent: string;
+    devMode: boolean;
+  };
+  xbExtension: object;
+  path: {
+    baseUrl: string;
+  };
+  editor: {
+    formats: {
+      [key: string]: FormatType;
+    };
+  };
+  ajaxPageState: {
+    libraries: string;
+    theme: string;
+    theme_token: string;
+  };
+}
diff --git a/ui/src/types/FormatType.ts b/ui/src/types/FormatType.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ab62c4c5340021fac0bbd8639f33b5c0e4fe57ed
--- /dev/null
+++ b/ui/src/types/FormatType.ts
@@ -0,0 +1,13 @@
+export interface FormatType {
+  format: string;
+  editor?: string;
+  editorSettings?: {
+    toolbar: any[];
+    plugins: string[];
+    config: {
+      [key: string]: any;
+    };
+    language: Record<string, any>;
+  };
+  [key: string]: any;
+}
diff --git a/ui/src/utils/drupal-globals.ts b/ui/src/utils/drupal-globals.ts
index 574755467f6ef502d97f7b684895c709beb55cdf..fecd4257e9f6f6460770b021491641526cf2bf47 100644
--- a/ui/src/utils/drupal-globals.ts
+++ b/ui/src/utils/drupal-globals.ts
@@ -1,7 +1,18 @@
-// @todo Refactor codebase to use these methods in https://drupal.org/i/3521811.
+import type { PropsValues } from '@/types/Form';
+import type { DrupalSettings } from '@/types/DrupalSettings';
+
 const { Drupal, drupalSettings } = window as any;
 
 export const getDrupal = () => Drupal;
-export const getDrupalSettings = () => drupalSettings;
+export const getDrupalSettings = (): DrupalSettings => drupalSettings;
 export const getXbSettings = () => drupalSettings.xb;
 export const getBaseUrl = () => drupalSettings.path.baseUrl;
+
+export const setXbDrupalSetting = (
+  property: 'layoutUtils' | 'navUtils',
+  value: PropsValues,
+) => {
+  if (drupalSettings?.xb?.[property]) {
+    drupalSettings.xb[property] = { ...drupalSettings.xb[property], ...value };
+  }
+};
diff --git a/ui/tests/vitest/support/vitest.setup.js b/ui/tests/vitest/support/vitest.setup.js
index 08aae24d56c1b5b16fe9ad59f8bb8763eb244c4a..d9adef1345346cca05e72dd39d02b665c74fd306 100644
--- a/ui/tests/vitest/support/vitest.setup.js
+++ b/ui/tests/vitest/support/vitest.setup.js
@@ -1,5 +1,12 @@
 import { vi } from 'vitest';
 
+const mockDrupalSettings = {
+  path: {
+    baseUrl: '/',
+  },
+  xb: {},
+};
+
 vi.stubGlobal('URL', {
   createObjectURL: vi.fn().mockImplementation((blob) => {
     return `mock-object-url/${blob.name}`;
@@ -10,14 +17,17 @@ vi.mock('@/utils/drupal-globals', () => ({
   getDrupal: () => ({
     url: (path) => `http://mock-drupal-url/${path}`,
   }),
-  getDrupalSettings: () => ({
-    path: {
-      baseUrl: '/',
-    },
-    xb: {},
-  }),
-  getXbSettings: () => ({}),
-  getBasePath: () => '/',
+  getDrupalSettings: () => mockDrupalSettings,
+  getXbSettings: () => mockDrupalSettings.xb,
+  getBasePath: () => mockDrupalSettings.path.baseUrl,
+  setXbDrupalSetting: (property, value) => {
+    if (mockDrupalSettings?.xb?.[property]) {
+      mockDrupalSettings.xb[property] = {
+        ...mockDrupalSettings.xb[property],
+        ...value,
+      };
+    }
+  },
 }));
 
 vi.mock('@swc/wasm-web', () => ({