diff --git a/client/jest.setup.js b/client/jest.setup.js
index ccc7ab57a7..c075aa4eb8 100644
--- a/client/jest.setup.js
+++ b/client/jest.setup.js
@@ -5,3 +5,35 @@ import 'regenerator-runtime/runtime';
 // See: https://github.com/testing-library/jest-dom
 // eslint-disable-next-line import/no-extraneous-dependencies
 import '@testing-library/jest-dom';
+
+// Mock matchMedia
+window.matchMedia = jest.fn().mockImplementation((query) => ({
+  matches: false,
+  media: query,
+  onchange: null,
+  addListener: jest.fn(), // Deprecated
+  removeListener: jest.fn(), // Deprecated
+  addEventListener: jest.fn(),
+  removeEventListener: jest.fn(),
+  dispatchEvent: jest.fn()
+}));
+
+// Mock localStorage
+const localStorageMock = (function () {
+  let store = {};
+  return {
+    getItem: jest.fn((key) => store[key] || null),
+    setItem: jest.fn((key, value) => {
+      store[key] = value.toString();
+    }),
+    removeItem: jest.fn((key) => {
+      delete store[key];
+    }),
+    clear: jest.fn(() => {
+      store = {};
+    })
+  };
+})();
+Object.defineProperty(window, 'localStorage', {
+  value: localStorageMock
+});
diff --git a/client/modules/App/components/ThemeProvider.jsx b/client/modules/App/components/ThemeProvider.jsx
index 8bbef6931e..b6d450099b 100644
--- a/client/modules/App/components/ThemeProvider.jsx
+++ b/client/modules/App/components/ThemeProvider.jsx
@@ -1,11 +1,62 @@
-import React from 'react';
+import React, { useEffect } from 'react';
 import PropTypes from 'prop-types';
-import { useSelector } from 'react-redux';
+import { useSelector, useDispatch } from 'react-redux';
 import { ThemeProvider } from 'styled-components';
-import theme from '../../../theme';
+import theme, { Theme } from '../../../theme';
+import { setTheme } from '../../IDE/actions/preferences';
 
 const Provider = ({ children }) => {
   const currentTheme = useSelector((state) => state.preferences.theme);
+  const dispatch = useDispatch();
+
+  // Detect system color scheme preference on initial load
+  useEffect(() => {
+    // Only apply system preference if the user hasn't explicitly set a theme
+    const userHasExplicitlySetTheme =
+      localStorage.getItem('has_set_theme') === 'true';
+    if (!userHasExplicitlySetTheme) {
+      const prefersDarkMode =
+        window.matchMedia &&
+        window.matchMedia('(prefers-color-scheme: dark)').matches;
+
+      if (prefersDarkMode) {
+        dispatch(setTheme(Theme.dark, { isSystemPreference: true }));
+      } else {
+        dispatch(setTheme(Theme.light, { isSystemPreference: true }));
+      }
+    }
+
+    // Listen for changes to system color scheme preference
+    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
+
+    const handleChange = (e) => {
+      if (localStorage.getItem('has_set_theme') !== 'true') {
+        dispatch(
+          setTheme(e.matches ? Theme.dark : Theme.light, {
+            isSystemPreference: true
+          })
+        );
+      }
+    };
+
+    // Add event listener with modern API if available
+    if (mediaQuery.addEventListener) {
+      mediaQuery.addEventListener('change', handleChange);
+    } else {
+      // Fallback for older browsers
+      mediaQuery.addListener(handleChange);
+    }
+
+    // Clean up event listener
+    return () => {
+      if (mediaQuery.removeEventListener) {
+        mediaQuery.removeEventListener('change', handleChange);
+      } else {
+        mediaQuery.removeListener(handleChange);
+      }
+    };
+  }, [dispatch]);
+
   return (
     <ThemeProvider theme={{ ...theme[currentTheme] }}>{children}</ThemeProvider>
   );
diff --git a/client/modules/IDE/actions/preferences.js b/client/modules/IDE/actions/preferences.js
index e0473bd995..defd242eed 100644
--- a/client/modules/IDE/actions/preferences.js
+++ b/client/modules/IDE/actions/preferences.js
@@ -177,7 +177,7 @@ export function setGridOutput(value) {
   };
 }
 
-export function setTheme(value) {
+export function setTheme(value, { isSystemPreference = false } = {}) {
   // return {
   //   type: ActionTypes.SET_THEME,
   //   value
@@ -187,6 +187,13 @@ export function setTheme(value) {
       type: ActionTypes.SET_THEME,
       value
     });
+
+    // If this is a user-initiated theme change (not from system preference),
+    // mark that the user has explicitly set a theme
+    if (!isSystemPreference) {
+      localStorage.setItem('has_set_theme', 'true');
+    }
+
     const state = getState();
     if (state.user.authenticated) {
       const formParams = {
diff --git a/client/modules/IDE/components/Preferences/Preferences.unit.test.jsx b/client/modules/IDE/components/Preferences/Preferences.unit.test.jsx
index 55f9827d23..fdba967652 100644
--- a/client/modules/IDE/components/Preferences/Preferences.unit.test.jsx
+++ b/client/modules/IDE/components/Preferences/Preferences.unit.test.jsx
@@ -256,6 +256,21 @@ describe('<Preferences />', () => {
   };
 
   describe('testing theme switching', () => {
+    beforeEach(() => {
+      // Mock localStorage for theme tests
+      Object.defineProperty(window, 'localStorage', {
+        value: {
+          getItem: jest.fn().mockImplementation((key) => {
+            if (key === 'has_set_theme') return 'true';
+            return null;
+          }),
+          setItem: jest.fn(),
+          removeItem: jest.fn()
+        },
+        writable: true
+      });
+    });
+
     describe('dark mode', () => {
       it('switch to light', () => {
         subject({ theme: 'dark' });
diff --git a/client/modules/IDE/components/Preferences/index.jsx b/client/modules/IDE/components/Preferences/index.jsx
index fa5859400e..bd09c8da9b 100644
--- a/client/modules/IDE/components/Preferences/index.jsx
+++ b/client/modules/IDE/components/Preferences/index.jsx
@@ -102,6 +102,29 @@ export default function Preferences() {
           <div className="preference">
             <h4 className="preference__title">{t('Preferences.Theme')}</h4>
             <div className="preference__options">
+              <input
+                type="radio"
+                onChange={() => {
+                  localStorage.removeItem('has_set_theme');
+                  const prefersDarkMode =
+                    window.matchMedia &&
+                    window.matchMedia('(prefers-color-scheme: dark)').matches;
+                  dispatch(
+                    setTheme(prefersDarkMode ? 'dark' : 'light', {
+                      isSystemPreference: true
+                    })
+                  );
+                }}
+                aria-label={t('Preferences.SystemThemeARIA')}
+                name="system theme"
+                id="system-theme-on"
+                className="preference__radio-button"
+                value="system"
+                checked={localStorage.getItem('has_set_theme') !== 'true'}
+              />
+              <label htmlFor="system-theme-on" className="preference__option">
+                {t('Preferences.SystemTheme')}
+              </label>
               <input
                 type="radio"
                 onChange={() => dispatch(setTheme('light'))}
@@ -110,7 +133,10 @@ export default function Preferences() {
                 id="light-theme-on"
                 className="preference__radio-button"
                 value="light"
-                checked={theme === 'light'}
+                checked={
+                  theme === 'light' &&
+                  localStorage.getItem('has_set_theme') === 'true'
+                }
               />
               <label htmlFor="light-theme-on" className="preference__option">
                 {t('Preferences.LightTheme')}
@@ -123,7 +149,10 @@ export default function Preferences() {
                 id="dark-theme-on"
                 className="preference__radio-button"
                 value="dark"
-                checked={theme === 'dark'}
+                checked={
+                  theme === 'dark' &&
+                  localStorage.getItem('has_set_theme') === 'true'
+                }
               />
               <label htmlFor="dark-theme-on" className="preference__option">
                 {t('Preferences.DarkTheme')}
@@ -136,7 +165,10 @@ export default function Preferences() {
                 id="high-contrast-theme-on"
                 className="preference__radio-button"
                 value="contrast"
-                checked={theme === 'contrast'}
+                checked={
+                  theme === 'contrast' &&
+                  localStorage.getItem('has_set_theme') === 'true'
+                }
               />
               <label
                 htmlFor="high-contrast-theme-on"
diff --git a/translations/locales/en-US/translations.json b/translations/locales/en-US/translations.json
index a60bcd83cd..cffa8a403e 100644
--- a/translations/locales/en-US/translations.json
+++ b/translations/locales/en-US/translations.json
@@ -172,6 +172,8 @@
     "GeneralSettings": "General settings",
     "Accessibility": "Accessibility",
     "Theme": "Theme",
+    "SystemTheme": "System Preference",
+    "SystemThemeARIA": "use system theme preference",
     "LightTheme": "Light",
     "LightThemeARIA": "light theme on",
     "DarkTheme": "Dark",
@@ -365,7 +367,7 @@
     "CreateTokenSubmit": "Create",
     "NoTokens": "You have no existing tokens.",
     "NewTokenTitle": "Your new access token",
-    "NewTokenInfo": "Make sure to copy your new personal access token now.\n                  You won’t be able to see it again!",
+    "NewTokenInfo": "Make sure to copy your new personal access token now.\n                  You won't be able to see it again!",
     "ExistingTokensTitle": "Existing tokens"
   },
   "APIKeyList": {