diff --git a/src/components/ToggleDarkMode.tsx b/src/components/ToggleDarkMode.tsx
new file mode 100644
index 00000000..a2bab9cc
--- /dev/null
+++ b/src/components/ToggleDarkMode.tsx
@@ -0,0 +1,33 @@
+import React, { useEffect, useState } from "react";
+import { ToggleDarkModeContainer } from "../styles/components/ToggleDarkMode";
+import DarkModeToggle from "react-dark-mode-toggle";
+import useAppStore from "../store/store";
+
+const ToggleDarkMode: React.FC = () => {
+ const { backgroundColor, toggleDarkMode } = useAppStore();
+ const [isDarkMode, setIsDarkMode] = useState(backgroundColor === "#121212");
+
+ useEffect(() => {
+ setIsDarkMode(backgroundColor === "#121212");
+ }, [backgroundColor]);
+
+ const handleChange = () => {
+ toggleDarkMode();
+ setIsDarkMode((prev) => !prev);
+ const newTheme = !isDarkMode ? "dark" : "light";
+ document.documentElement.setAttribute("data-theme", newTheme);
+ };
+
+ return (
+
+
+
+ );
+};
+
+export default ToggleDarkMode;
diff --git a/src/styles/components/ToggleDarkMode.ts b/src/styles/components/ToggleDarkMode.ts
new file mode 100644
index 00000000..c5ca01b3
--- /dev/null
+++ b/src/styles/components/ToggleDarkMode.ts
@@ -0,0 +1,17 @@
+import styled from "styled-components";
+
+export const ToggleDarkModeContainer = styled.div`
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 1rem;
+
+ /* Prevent clicks on the outer container */
+ pointer-events: none;
+
+ .dark-mode-toggle {
+ pointer-events: auto; /* Enable clicks only inside the actual toggle */
+ outline: 0.125rem solid white;
+ border-radius: 1.25rem;
+ }
+`;
diff --git a/src/tests/components/ToggleDarkMode.test.tsx b/src/tests/components/ToggleDarkMode.test.tsx
new file mode 100644
index 00000000..c5e329cd
--- /dev/null
+++ b/src/tests/components/ToggleDarkMode.test.tsx
@@ -0,0 +1,151 @@
+import { describe, it, expect, vi, beforeEach } from 'vitest';
+import { render, screen, fireEvent } from '@testing-library/react';
+import '@testing-library/jest-dom';
+
+// ---------- Mutable store state ----------
+let mockBackgroundColor = '#ffffff';
+const mockToggleDarkMode = vi.fn();
+
+vi.mock('../../store/store', () => {
+ // Return a function that, when called with no selector, returns the store object.
+ // When called with a selector, passes the store object through the selector.
+ const useAppStore = (...args: unknown[]) => {
+ const storeState = {
+ backgroundColor: mockBackgroundColor,
+ toggleDarkMode: mockToggleDarkMode,
+ };
+ if (typeof args[0] === 'function') {
+ return (args[0] as (s: typeof storeState) => unknown)(storeState);
+ }
+ return storeState;
+ };
+ return { default: useAppStore };
+});
+
+// ---------- Mock react-dark-mode-toggle ----------
+vi.mock('react-dark-mode-toggle', () => ({
+ default: ({
+ checked,
+ onChange,
+ size,
+ className,
+ }: {
+ checked: boolean;
+ onChange: () => void;
+ size: number;
+ className: string;
+ }) => (
+
+ ),
+}));
+
+// ---------- Mock styled-component ----------
+vi.mock('../../styles/components/ToggleDarkMode', () => ({
+ ToggleDarkModeContainer: ({
+ children,
+ ...props
+ }: React.PropsWithChildren>) => (
+ {children}
+ ),
+}));
+
+// ---------- Import after mocks ----------
+import ToggleDarkMode from '../../components/ToggleDarkMode';
+
+// ---------- Tests ----------
+describe('ToggleDarkMode', () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ mockBackgroundColor = '#ffffff';
+ document.documentElement.removeAttribute('data-theme');
+ });
+
+ it('renders the toggle component', () => {
+ render();
+ expect(screen.getByTestId('toggle-dark-mode')).toBeInTheDocument();
+ });
+
+ it('initializes isDarkMode to false when backgroundColor is #ffffff', () => {
+ mockBackgroundColor = '#ffffff';
+ render();
+ const btn = screen.getByTestId('dark-mode-toggle');
+ expect(btn.getAttribute('data-checked')).toBe('false');
+ });
+
+ it('initializes isDarkMode to true when backgroundColor is #121212', () => {
+ mockBackgroundColor = '#121212';
+ render();
+ const btn = screen.getByTestId('dark-mode-toggle');
+ expect(btn.getAttribute('data-checked')).toBe('true');
+ });
+
+ it('calls toggleDarkMode when clicked', () => {
+ render();
+ fireEvent.click(screen.getByTestId('dark-mode-toggle'));
+ expect(mockToggleDarkMode).toHaveBeenCalledTimes(1);
+ });
+
+ it('sets data-theme to dark when toggled from light mode', () => {
+ mockBackgroundColor = '#ffffff';
+ render();
+ fireEvent.click(screen.getByTestId('dark-mode-toggle'));
+ expect(document.documentElement.getAttribute('data-theme')).toBe('dark');
+ });
+
+ it('sets data-theme to light when toggled from dark mode', () => {
+ mockBackgroundColor = '#121212';
+ render();
+ fireEvent.click(screen.getByTestId('dark-mode-toggle'));
+ expect(document.documentElement.getAttribute('data-theme')).toBe('light');
+ });
+
+ it('updates isDarkMode when backgroundColor prop changes', () => {
+ mockBackgroundColor = '#ffffff';
+ const { rerender } = render();
+
+ const btn = screen.getByTestId('dark-mode-toggle');
+ expect(btn.getAttribute('data-checked')).toBe('false');
+
+ // Simulate store change
+ mockBackgroundColor = '#121212';
+ rerender();
+
+ expect(btn.getAttribute('data-checked')).toBe('true');
+ });
+
+ it('passes size={60} to the toggle', () => {
+ render();
+ const btn = screen.getByTestId('dark-mode-toggle');
+ expect(btn.getAttribute('data-size')).toBe('60');
+ });
+
+ it('applies className dark-mode-toggle', () => {
+ render();
+ const btn = screen.getByTestId('dark-mode-toggle');
+ expect(btn.className).toBe('dark-mode-toggle');
+ });
+
+ it('handles multiple sequential toggles correctly', () => {
+ mockBackgroundColor = '#ffffff';
+ render();
+ const btn = screen.getByTestId('dark-mode-toggle');
+
+ // First click: light → dark
+ fireEvent.click(btn);
+ expect(document.documentElement.getAttribute('data-theme')).toBe('dark');
+ expect(mockToggleDarkMode).toHaveBeenCalledTimes(1);
+
+ // Second click: dark → light
+ fireEvent.click(btn);
+ expect(document.documentElement.getAttribute('data-theme')).toBe('light');
+ expect(mockToggleDarkMode).toHaveBeenCalledTimes(2);
+ });
+});