diff --git a/ui/src/Pages/SettingsPage/SettingsPage.tsx b/ui/src/Pages/SettingsPage/SettingsPage.tsx
index 6febb71..e9769cd 100644
--- a/ui/src/Pages/SettingsPage/SettingsPage.tsx
+++ b/ui/src/Pages/SettingsPage/SettingsPage.tsx
@@ -18,7 +18,7 @@ export const SectionTitle = ({ children, nospace }: SectionTitleProps) => {
   return (
     <h2
       className={classNames(
-        'pb-1 border-b border-gray-200 text-xl mb-5',
+        'pb-1 border-b border-gray-200 dark:border-[#3B3B3B] text-xl mb-5',
         !nospace && 'mt-6'
       )}
     >
diff --git a/ui/src/Pages/SettingsPage/UserPreferences.tsx b/ui/src/Pages/SettingsPage/UserPreferences.tsx
index 8f59602..79e7984 100644
--- a/ui/src/Pages/SettingsPage/UserPreferences.tsx
+++ b/ui/src/Pages/SettingsPage/UserPreferences.tsx
@@ -1,6 +1,6 @@
 import { useMutation, useQuery } from '@apollo/client'
 import gql from 'graphql-tag'
-import React, { useMemo } from 'react'
+import React, { useMemo, useState } from 'react'
 import { useTranslation } from 'react-i18next'
 import styled from 'styled-components'
 import { LanguageTranslation } from '../../__generated__/globalTypes'
@@ -16,6 +16,8 @@ import {
   changeUserPreferencesVariables,
 } from './__generated__/changeUserPreferences'
 import { myUserPreferences } from './__generated__/myUserPreferences'
+import { TranslationFn } from '../../localization'
+import { changeTheme, getTheme } from '../../theme'
 
 const languagePreferences = [
   { key: 1, label: 'English', flag: 'uk', value: LanguageTranslation.English },
@@ -47,6 +49,24 @@ const languagePreferences = [
   },
 ]
 
+const themePreferences = (t: TranslationFn) => [
+  {
+    key: 1,
+    label: t('settings.user_preferences.theme.auto.label', 'Same as system'),
+    value: 'auto',
+  },
+  {
+    key: 2,
+    label: t('settings.user_preferences.theme.light.label', 'Light'),
+    value: 'light',
+  },
+  {
+    key: 2,
+    label: t('settings.user_preferences.theme.dark.label', 'Dark'),
+    value: 'dark',
+  },
+]
+
 const CHANGE_USER_PREFERENCES = gql`
   mutation changeUserPreferences($language: String) {
     changeUserPreferences(language: $language) {
@@ -86,6 +106,12 @@ const UserPreferencesWrapper = styled.div`
 
 const UserPreferences = () => {
   const { t } = useTranslation()
+  const [theme, setTheme] = useState(getTheme())
+
+  const changeStateTheme = (value: string) => {
+    changeTheme(value)
+    setTheme(value)
+  }
 
   const { data } = useQuery<myUserPreferences>(MY_USER_PREFERENCES)
 
@@ -109,7 +135,7 @@ const UserPreferences = () => {
         {t('settings.user_preferences.title', 'User preferences')}
       </SectionTitle>
       <LogoutButton />
-      <label id="user_pref_change_language_field">
+      <label htmlFor="user_pref_change_language_field">
         <InputLabelTitle>
           {t(
             'settings.user_preferences.change_language.label',
@@ -140,6 +166,23 @@ const UserPreferences = () => {
         selected={data?.myUserPreferences.language || undefined}
         disabled={loadingPrefs}
       />
+      <label htmlFor="user_pref_change_theme_field">
+        <InputLabelTitle>
+          {t('settings.user_preferences.theme.title', 'Theme preferences')}
+        </InputLabelTitle>
+        <InputLabelDescription>
+          {t(
+            'settings.user_preferences.theme.description',
+            'Change the appearance of the website'
+          )}
+        </InputLabelDescription>
+      </label>
+      <Dropdown
+        id="user_pref_change_theme_field"
+        items={themePreferences(t)}
+        setSelected={changeStateTheme}
+        selected={theme}
+      />
     </UserPreferencesWrapper>
   )
 }
diff --git a/ui/src/index.css b/ui/src/index.css
index 299943b..63ef980 100644
--- a/ui/src/index.css
+++ b/ui/src/index.css
@@ -12,7 +12,8 @@ html {
   font-family: 'Source Sans Pro', sans-serif;
 }
 
-body.dark {
+body.dark,
+html.dark {
   @apply bg-dark-bg text-dark-text;
 }
 
diff --git a/ui/src/index.tsx b/ui/src/index.tsx
index 8024eff..b39c603 100644
--- a/ui/src/index.tsx
+++ b/ui/src/index.tsx
@@ -7,11 +7,13 @@ import client from './apolloClient'
 import { ApolloProvider } from '@apollo/client'
 import { BrowserRouter as Router } from 'react-router-dom'
 import { setupLocalization } from './localization'
+import { updateTheme } from './theme'
 import * as serviceWorkerRegistration from './serviceWorkerRegistration'
 
 import './index.css'
 import { SidebarProvider } from './components/sidebar/Sidebar'
 
+updateTheme()
 setupLocalization()
 
 const Main = () => (
@@ -24,8 +26,6 @@ const Main = () => (
   </ApolloProvider>
 )
 
-document.getElementsByTagName('body')[0].classList.add('dark')
-
 ReactDOM.render(<Main />, document.getElementById('root'))
 
 serviceWorkerRegistration.register()
diff --git a/ui/src/theme.ts b/ui/src/theme.ts
new file mode 100644
index 0000000..9599b81
--- /dev/null
+++ b/ui/src/theme.ts
@@ -0,0 +1,34 @@
+export const updateTheme = () => {
+  if (
+    localStorage.theme === 'dark' ||
+    (!('theme' in localStorage) &&
+      window.matchMedia('(prefers-color-scheme: dark)').matches)
+  ) {
+    document.documentElement.classList.add('dark')
+  } else {
+    document.documentElement.classList.remove('dark')
+  }
+}
+
+export const changeTheme = (value: string) => {
+  if (value == 'light') {
+    localStorage.theme = 'light'
+  } else if (value == 'dark') {
+    localStorage.theme = 'dark'
+  } else {
+    // use OS preference
+    localStorage.removeItem('theme')
+  }
+
+  updateTheme()
+}
+
+export const getTheme = () => {
+  if (localStorage.theme == 'light') {
+    return 'light'
+  } else if (localStorage.theme == 'dark') {
+    return 'dark'
+  } else {
+    return 'auto'
+  }
+}
