diff --git a/assets/js/theme.js b/assets/js/theme.js
index 395251dda3d2b6499ea6a0404a711468dd33e8e4..32ad7d7987cdfe23dfabbe6749e57a0cb9ea4239 100644
--- a/assets/js/theme.js
+++ b/assets/js/theme.js
@@ -1,47 +1,53 @@
 const initTheme = () => {
-    // Check for saved theme preference or default to system preference
-    const savedTheme = localStorage.getItem('theme') || 
-      (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
-    
-    // Apply initial theme
-    document.documentElement.setAttribute('data-theme', savedTheme);
-    if (savedTheme === 'dark') {
+  // Check if user is logged in
+  if (window.currentUser) {
+    // For logged-in users, use their database preference
+    const userDarkMode = window.userDarkMode === true;
+    applyTheme(userDarkMode ? 'dark' : 'light');
+  } else {
+    // For non-authenticated users, use localStorage
+    const savedTheme = localStorage.getItem('theme') || 'light';
+    applyTheme(savedTheme);
+  }
+
+  // Helper function to apply theme
+  function applyTheme(theme) {
+    if (theme === 'dark') {
       document.documentElement.classList.add('dark');
+    } else {
+      document.documentElement.classList.remove('dark');
     }
-  
-    // Add click handler to theme toggle button
-    document.addEventListener('click', (e) => {
-      const themeToggle = e.target.closest('[data-theme-toggle]');
-      if (themeToggle) {
-        const currentTheme = localStorage.getItem('theme') || 'light';
-        const newTheme = currentTheme === 'light' ? 'dark' : 'light';
-        
-        // Update localStorage
-        localStorage.setItem('theme', newTheme);
-        
-        // Update document classes and data attributes
-        document.documentElement.setAttribute('data-theme', newTheme);
-        if (newTheme === 'dark') {
-          document.documentElement.classList.add('dark');
-        } else {
-          document.documentElement.classList.remove('dark');
+    localStorage.setItem('theme', theme);
+  }
+
+  // Add click handler to theme toggle button
+  document.addEventListener('click', async (e) => {
+    const themeToggle = e.target.closest('[data-theme-toggle]');
+    if (themeToggle) {
+      const isDark = !document.documentElement.classList.contains('dark');
+      const newTheme = isDark ? 'dark' : 'light';
+      
+      // Apply theme change
+      applyTheme(newTheme);
+
+      // If user is logged in, save preference to server
+      if (window.currentUser) {
+        try {
+          await fetch('/api/update_theme', {
+            method: 'POST',
+            headers: {
+              'Content-Type': 'application/json',
+              'X-CSRF-Token': document.querySelector("meta[name='csrf-token']").content
+            },
+            credentials: 'same-origin',
+            body: JSON.stringify({ is_dark_mode: isDark })
+          });
+        } catch (error) {
+          console.error('Error updating theme preference:', error);
         }
       }
-    });
-  
-    // Listen for system theme changes
-    window.matchMedia('(prefers-color-scheme: dark)')
-      .addEventListener('change', e => {
-        if (!localStorage.getItem('theme')) {
-          const newTheme = e.matches ? 'dark' : 'light';
-          document.documentElement.setAttribute('data-theme', newTheme);
-          if (newTheme === 'dark') {
-            document.documentElement.classList.add('dark');
-          } else {
-            document.documentElement.classList.remove('dark');
-          }
-        }
-      });
-  };
-  
-  export default initTheme;
\ No newline at end of file
+    }
+  });
+};
+
+export default initTheme;
\ No newline at end of file
diff --git a/features/contexts/dark_mode_context.exs b/features/contexts/dark_mode_context.exs
index 1c7e324fa4076986a593a82588cb26c7a55db15a..05057a262ea1def2d829cb1fdc11f31e0e981daa 100644
--- a/features/contexts/dark_mode_context.exs
+++ b/features/contexts/dark_mode_context.exs
@@ -19,11 +19,18 @@ defmodule DarkModeContext do
 
   given_ ~r/^there exists following accounts$/, fn state, %{table_data: table} ->
     table
-    |> Enum.map(fn user_details -> User.changeset(%User{}, user_details) end)
+    |> Enum.map(fn user_details ->
+      # Handle is_dark_mode if present
+      user_details = case Map.get(user_details, :is_dark_mode) do
+        nil -> user_details
+        value when is_binary(value) -> Map.put(user_details, :is_dark_mode, value == "true")
+        _ -> user_details
+      end
+      User.changeset(%User{}, user_details)
+    end)
     |> Enum.each(fn changeset -> Repo.insert!(changeset) end)
 
     user = List.last(table)
-
     {
       :ok,
       state
@@ -93,23 +100,27 @@ defmodule DarkModeContext do
   when_ ~r/^I visit the property details page$/, fn state ->
     property = hd(state.advertisements)
     navigate_to("/properties/#{property.reference}")
-    :timer.sleep(1000)
+    :timer.sleep(500)
     {:ok, state}
   end
 
   # Light mode assertions
   then_ ~r/^I should see the application in light mode$/, fn state ->
-    assert get_css_variable("--color-background") == "#ffffff"
-    assert get_css_variable("--color-text") == "#1a1a1a"
-    assert get_css_variable("--color-card") == "#ffffff"
+    :timer.sleep(500)
+    html_classes = find_element(:css, "html") |> attribute_value("class")
+    refute String.contains?(html_classes, "dark")
+    assert has_classes?("body", ["bg-white", "text-zinc-900"])
+    assert element_displayed?(find_element(:css, ".theme-toggle-button .hero-moon-solid"))
     {:ok, state}
   end
 
   # Dark mode assertions
   then_ ~r/^I should see the application in dark mode$/, fn state ->
-    assert get_css_variable("--color-background") == "#0f172a"
-    assert get_css_variable("--color-text") == "#e2e8f0"
-    assert get_css_variable("--color-card") == "#1e293b"
+    :timer.sleep(500)
+    html_classes = find_element(:css, "html") |> attribute_value("class")
+    assert String.contains?(html_classes, "dark")
+    assert has_classes?("body", ["dark:bg-dark-background", "dark:text-dark-text"])
+    assert element_displayed?(find_element(:css, ".theme-toggle-button .hero-sun-solid"))
     {:ok, state}
   end
 
@@ -123,7 +134,8 @@ defmodule DarkModeContext do
   end
 
   then_ ~r/^the background should be dark$/, fn state ->
-    assert get_css_variable("--color-background") == "#0f172a"
+    :timer.sleep(500)
+    assert has_classes?("body", ["dark:bg-dark-background"])
     {:ok, state}
   end
 
@@ -146,7 +158,8 @@ defmodule DarkModeContext do
   end
 
   then_ ~r/^the text should be light colored$/, fn state ->
-    assert get_css_variable("--color-text") == "#e2e8f0"
+    :timer.sleep(500)
+    assert has_classes?("body", ["dark:text-dark-text"])  # Using the actual class from your HTML
     {:ok, state}
   end
 
@@ -171,17 +184,30 @@ defmodule DarkModeContext do
       end))}
   end
 
+  defp setup_session(email, password) do
+    fill_field({:id, "email"}, email)
+    fill_field({:id, "password"}, password)
+    click({:id, "login_button"})
+  end
+
   defp get_css_variable(variable_name) do
     script = """
-    var style = getComputedStyle(document.documentElement);
-    return style.getPropertyValue('#{variable_name}').trim();
+    var root = document.documentElement;
+    var theme = root.getAttribute('data-theme');
+    var style = getComputedStyle(root);
+    var value = style.getPropertyValue('#{variable_name}').trim();
+    console.log('Theme:', theme, 'Variable:', '#{variable_name}', 'Value:', value);
+    return value;
     """
     execute_script(script)
   end
 
-  defp setup_session(email, password) do
-    fill_field({:id, "email"}, email)
-    fill_field({:id, "password"}, password)
-    click({:id, "login_button"})
+  defp get_element_classes(selector) do
+    find_element(:css, selector) |> attribute_value("class")
+  end
+
+  defp has_classes?(selector, classes) when is_list(classes) do
+    element_classes = get_element_classes(selector)
+    Enum.all?(classes, &String.contains?(element_classes, &1))
   end
  end
diff --git a/features/dark_mode.feature b/features/dark_mode.feature
index d8528033e1938954dc81cb2b079fd16deb12b761..b8615dca3125a8ca9cb54e4966c94ea9b0065f58 100644
--- a/features/dark_mode.feature
+++ b/features/dark_mode.feature
@@ -13,18 +13,29 @@ Feature: FR-21: Dark/Light mode appearance switch
     And the background should be dark
     And the text should be light colored
 
-  Scenario: Dark mode persists across pages
+  Scenario: Dark mode user preference persists across pages
     Given there exists following accounts
-            | name     | surname | birth_date | phone_number | email                      | password | confirm_password |
-            | Existing | Account | 2000-01-01 | 000          | existing.account@gmail.com | password | password         |
-    And I have enabled dark mode
+      | name     | surname | birth_date | phone_number | email                      | password | confirm_password | is_dark_mode |
+      | Existing | Account | 2000-01-01 | 000          | existing.account@gmail.com | password | password         | true        |
     When I navigate to the login page
-    Then I should see the login page in dark mode
     And I am logged in
+    Then I should see the application in dark mode
     When I navigate to the profile page
-    Then I should see the profile page in dark mode
+    Then I should see the application in dark mode
     When I navigate to the home page
-    Then I should see the home page in dark mode
+    Then I should see the application in dark mode
+
+  Scenario: Light mode user preference persists across pages
+    Given there exists following accounts
+      | name     | surname | birth_date | phone_number | email                      | password | confirm_password | is_dark_mode |
+      | Existing | Account | 2000-01-01 | 000          | existing.account@gmail.com | password | password         | false        |
+    When I navigate to the login page
+    And I am logged in
+    Then I should see the application in light mode
+    When I navigate to the profile page
+    Then I should see the application in light mode
+    When I navigate to the home page
+    Then I should see the application in light mode
 
   Scenario: Theme preference persists after refresh
     Given I have enabled dark mode
@@ -43,6 +54,6 @@ Feature: FR-21: Dark/Light mode appearance switch
     Then I should see dark mode colors for:
       | Element            | Color    |
       | Background        | #0f172a  |
-      # | Text             | #e2e8f0  |
-      # | Cards            | #1e293b  |
-      # | Buttons          | #60a5fa  |
\ No newline at end of file
+      | Text             | #e2e8f0  |
+      | Cards            | #1e293b  |
+      | Buttons          | #60a5fa  |
\ No newline at end of file
diff --git a/lib/proptrackr/accounts/user.ex b/lib/proptrackr/accounts/user.ex
index 37f73eb90cb952bdc96ec5eb76dbc0b67452a4a8..2f23ababf6a28b371340905e6294e2b501418753 100644
--- a/lib/proptrackr/accounts/user.ex
+++ b/lib/proptrackr/accounts/user.ex
@@ -14,6 +14,7 @@ defmodule PropTrackr.Accounts.User do
     field :email, :string
     field :password, :string
     field :confirm_password, :string, virtual: true  # Define confirm_password as virtual, not includes in database
+    field :is_dark_mode, :boolean, default: false
 
     has_many :properties, PropTrackr.Properties.Property
     has_many :searches, PropTrackr.Search
@@ -23,7 +24,7 @@ defmodule PropTrackr.Accounts.User do
 
   def changeset(struct, params \\ %{}) do
     struct
-    |> cast(params, [:name, :surname, :birth_date, :phone_number, :bio, :email, :password, :confirm_password])
+    |> cast(params, [:name, :surname, :birth_date, :phone_number, :bio, :email, :password, :confirm_password, :is_dark_mode])
     |> validate_required([:name, :surname, :birth_date, :phone_number, :email, :password, :confirm_password])
     |> validate_format(:name, ~r/^[a-zA-Z\s-]+$/, message: "must contain only English letters, spaces, or hyphens")
     |> validate_format(:surname, ~r/^[a-zA-Z\s-]+$/, message: "must contain only English letters, spaces, or hyphens")
@@ -96,4 +97,10 @@ defmodule PropTrackr.Accounts.User do
     end
   end
 
+  def update_theme_preference(user, is_dark) do
+    user
+    |> cast(%{is_dark_mode: is_dark}, [:is_dark_mode])
+    |> PropTrackr.Repo.update()
+  end
+
 end
diff --git a/lib/proptrackr_web/components/layouts/root.html.heex b/lib/proptrackr_web/components/layouts/root.html.heex
index 6c40d4c24b404912496efbe8930ad9575aafb87e..c631faee131bdf381fa883acf25b52c2f9db1bb1 100644
--- a/lib/proptrackr_web/components/layouts/root.html.heex
+++ b/lib/proptrackr_web/components/layouts/root.html.heex
@@ -1,5 +1,12 @@
 <!DOCTYPE html>
-<html lang="en" class="[scrollbar-gutter:stable] dark:dark" data-theme="light">
+<html lang="en" 
+  class={
+    cond do
+      assigns[:current_user] && assigns[:current_user].is_dark_mode -> "[scrollbar-gutter:stable] dark"
+      assigns[:current_user] -> "[scrollbar-gutter:stable]"
+      true -> "[scrollbar-gutter:stable]"  # For non-authenticated users, initial class will be set by JS
+    end
+  }>
   <head>
     <meta charset="utf-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1" />
@@ -8,10 +15,16 @@
       <%= assigns[:page_title] || "PropTrackr" %>
     </.live_title>
     <link phx-track-static rel="stylesheet" href={~p"/assets/app.css"} />
+    
+    <script>
+      window.currentUser = <%= if assigns[:current_user], do: "true", else: "false" %>;
+      window.userDarkMode = <%= if assigns[:current_user], do: "#{assigns[:current_user].is_dark_mode}", else: "null" %>;
+    </script>
+    
     <script defer phx-track-static type="text/javascript" src={~p"/assets/app.js"}>
     </script>
   </head>
- <body class="bg-white dark:bg-dark-background text-zinc-900 dark:text-dark-text transition-colors duration-300">
+  <body class="bg-white dark:bg-dark-background text-zinc-900 dark:text-dark-text transition-colors duration-300">
     <%= @inner_content %>
   </body>
-</html>
+</html>
\ No newline at end of file
diff --git a/lib/proptrackr_web/controllers/theme_controller.ex b/lib/proptrackr_web/controllers/theme_controller.ex
new file mode 100644
index 0000000000000000000000000000000000000000..927eeb6636bf2c3e3d65e71ee2accfb501297c6d
--- /dev/null
+++ b/lib/proptrackr_web/controllers/theme_controller.ex
@@ -0,0 +1,30 @@
+# lib/proptrackr_web/controllers/theme_controller.ex
+defmodule PropTrackrWeb.ThemeController do
+  use PropTrackrWeb, :controller
+  alias PropTrackr.Accounts.User
+  alias PropTrackr.Repo
+
+  def update(conn, %{"is_dark_mode" => is_dark_mode}) do
+    case conn.assigns.current_user do
+      nil ->
+        conn
+        |> put_status(:unauthorized)
+        |> json(%{error: "User not authenticated"})
+
+      user ->
+        # Update user directly using Repo
+        case Repo.update(Ecto.Changeset.change(user, %{is_dark_mode: is_dark_mode})) do
+          {:ok, updated_user} ->
+            # Update session with new theme preference
+            conn
+            |> put_session(:user_theme, updated_user.is_dark_mode)
+            |> json(%{success: true, is_dark_mode: updated_user.is_dark_mode})
+
+          {:error, _changeset} ->
+            conn
+            |> put_status(:unprocessable_entity)
+            |> json(%{error: "Could not update theme preference"})
+        end
+    end
+  end
+end
diff --git a/lib/proptrackr_web/router.ex b/lib/proptrackr_web/router.ex
index f08c304ea8bd401b91df75b5ac2cfdfcff368d56..330a15f977e207df8f27865d7d66551a5d964d4c 100644
--- a/lib/proptrackr_web/router.ex
+++ b/lib/proptrackr_web/router.ex
@@ -62,6 +62,7 @@ defmodule PropTrackrWeb.Router do
     post "/properties/calculate_price", PropertiesController, :calculate_price
     post "/properties/:reference/interest", InterestController, :create
     delete "/properties/:reference/interest", InterestController, :delete
+    post "/update_theme", ThemeController, :update
   end
 
   # Other scopes may use custom stacks.
diff --git a/priv/repo/migrations/20241206140323_add_dark_mode_to_users.exs b/priv/repo/migrations/20241206140323_add_dark_mode_to_users.exs
new file mode 100644
index 0000000000000000000000000000000000000000..27819cb2d9091011aece18ec949ce8a8e2c1b631
--- /dev/null
+++ b/priv/repo/migrations/20241206140323_add_dark_mode_to_users.exs
@@ -0,0 +1,9 @@
+defmodule PropTrackr.Repo.Migrations.AddDarkModeToUsers do
+  use Ecto.Migration
+
+  def change do
+    alter table(:users) do
+      add :is_dark_mode, :boolean, default: false, null: false
+    end
+  end
+end
diff --git a/test/proptrackr_web/controllers/theme_controller_test.exs b/test/proptrackr_web/controllers/theme_controller_test.exs
new file mode 100644
index 0000000000000000000000000000000000000000..d9bd7137ac73ba6bf37721c99a4da784b8496ac8
--- /dev/null
+++ b/test/proptrackr_web/controllers/theme_controller_test.exs
@@ -0,0 +1,104 @@
+defmodule PropTrackrWeb.ThemeControllerTest do
+  use PropTrackrWeb.ConnCase
+  alias PropTrackr.Accounts.User
+  alias PropTrackr.Repo
+
+  setup do
+    user = %User{
+      name: "Test",
+      surname: "User",
+      birth_date: ~D[2000-01-01],
+      phone_number: "000",
+      bio: "Yo",
+      email: "test.user@gmail.com",
+      password: "testing",
+      confirm_password: "testing",
+      is_dark_mode: false
+    }
+    user = Repo.insert!(user)
+
+    other_user = %User{
+      name: "Other",
+      surname: "User",
+      birth_date: ~D[2000-01-01],
+      phone_number: "111",
+      bio: "Hey",
+      email: "other.user@gmail.com",
+      password: "testing",
+      confirm_password: "testing",
+      is_dark_mode: true
+    }
+    other_user = Repo.insert!(other_user)
+
+    {:ok, %{user: user, other_user: other_user}}
+  end
+
+  test "authenticated user can enable dark mode", %{conn: conn, user: user} do
+    conn = conn |> setup_session(user)
+    conn = post(conn, ~p"/api/update_theme", %{"is_dark_mode" => true})
+
+    assert json_response(conn, 200) == %{
+      "success" => true,
+      "is_dark_mode" => true
+    }
+
+    updated_user = Repo.get!(User, user.id)
+    assert updated_user.is_dark_mode == true
+  end
+
+  test "authenticated user can disable dark mode", %{conn: conn, other_user: user} do
+    conn = conn |> setup_session(user)
+    conn = post(conn, ~p"/api/update_theme", %{"is_dark_mode" => false})
+
+    assert json_response(conn, 200) == %{
+      "success" => true,
+      "is_dark_mode" => false
+    }
+
+    updated_user = Repo.get!(User, user.id)
+    assert updated_user.is_dark_mode == false
+  end
+
+  test "unauthenticated user cannot update theme", %{conn: conn} do
+    conn = post(conn, ~p"/api/update_theme", %{"is_dark_mode" => true})
+
+    assert json_response(conn, 401) == %{
+      "error" => "User not authenticated"
+    }
+  end
+
+  test "theme preference persists in session", %{conn: conn, user: user} do
+    conn = conn |> setup_session(user)
+    conn = post(conn, ~p"/api/update_theme", %{"is_dark_mode" => true})
+
+    assert get_session(conn, :user_theme) == true
+
+    updated_user = Repo.get!(User, user.id)
+    assert updated_user.is_dark_mode == true
+  end
+
+  test "user can toggle theme multiple times", %{conn: conn, user: user} do
+    conn = conn |> setup_session(user)
+
+    # Enable dark mode
+    conn = post(conn, ~p"/api/update_theme", %{"is_dark_mode" => true})
+    assert json_response(conn, 200) == %{"success" => true, "is_dark_mode" => true}
+
+    # Disable dark mode
+    conn = post(conn, ~p"/api/update_theme", %{"is_dark_mode" => false})
+    assert json_response(conn, 200) == %{"success" => true, "is_dark_mode" => false}
+
+    # Enable dark mode again
+    conn = post(conn, ~p"/api/update_theme", %{"is_dark_mode" => true})
+    assert json_response(conn, 200) == %{"success" => true, "is_dark_mode" => true}
+
+    updated_user = Repo.get!(User, user.id)
+    assert updated_user.is_dark_mode == true
+  end
+
+  defp setup_session(conn, user) do
+    conn = conn |> post("/login", email: user.email, password: user.password)
+    conn = get conn, redirected_to(conn)
+    conn
+  end
+end