diff --git a/public/media/applications/icons/settings.svg b/public/media/applications/icons/settings.svg
new file mode 100644
index 0000000..c0b8c14
--- /dev/null
+++ b/public/media/applications/icons/settings.svg
@@ -0,0 +1,18 @@
+
diff --git a/src/components/applications/settings/Settings.jsx b/src/components/applications/settings/Settings.jsx
new file mode 100644
index 0000000..236f809
--- /dev/null
+++ b/src/components/applications/settings/Settings.jsx
@@ -0,0 +1,65 @@
+import { useEffect, useState } from "react";
+import styles from "./Settings.module.css";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faPalette } from "@fortawesome/free-solid-svg-icons";
+import { useVirtualRoot } from "../../../hooks/virtual-drive/VirtualRootContext.js";
+import { useSettings } from "../../../hooks/settings/SettingsContext.js";
+import { SettingsManager } from "../../../features/settings/settings.js";
+// eslint-disable-next-line no-unused-vars
+import { VirtualRoot } from "../../../features/virtual-drive/virtual-root.js";
+
+/**
+ * @param {Object} props
+ * @param {VirtualRoot} props.virtualRoot
+ * @param {SettingsManager} props.settingsManager
+ */
+function AppearanceTab({ virtualRoot, settingsManager }) {
+ const [wallpaper, setWallpaper] = useState(null);
+ const settings = settingsManager.get(SettingsManager.VIRTUAL_PATHS.desktop);
+
+ useEffect(() => {
+ settings.get("wallpaper", setWallpaper);
+ }, [settings]);
+
+ const onChange = (event) => {
+ const value = event.target.value;
+ settings.set("wallpaper", value);
+ }
+
+ return (
+
+ );
+}
+
+export function Settings() {
+ const [tabIndex, setTabIndex] = useState(0);
+ const virtualRoot = useVirtualRoot();
+ const settingsManager = useSettings();
+
+ return (
+
+
+
+
+
+ {tabIndex === 0
+ ?
+ : null
+ }
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/applications/settings/Settings.module.css b/src/components/applications/settings/Settings.module.css
new file mode 100644
index 0000000..86e3bfa
--- /dev/null
+++ b/src/components/applications/settings/Settings.module.css
@@ -0,0 +1,89 @@
+.Container {
+ --tabs-width: 10rem;
+
+ flex: 1;
+ display: flex;
+ width: 100%;
+ height: 100%;
+ background-color: var(--background-color-c);
+}
+
+.Tabs {
+ display: flex;
+ gap: 0.25rem;
+ flex-direction: column;
+ min-width: calc(var(--tabs-width) / 2);
+ width: var(--tabs-width);
+ height: 100%;
+ max-width: 50%;
+ padding: 0.5rem;
+ background-color: var(--background-color-b);
+ resize: horizontal;
+ overflow: hidden;
+}
+
+.Tab-button {
+ display: flex;
+ gap: 0.5rem;
+ align-items: center;
+ width: 100%;
+ padding: 0.5rem;
+ background: none;
+ border: none;
+ border-radius: 0.5rem;
+ outline: none;
+ cursor: pointer;
+ transition: background-color 100ms ease-in-out;
+}
+
+.Tab-button:hover {
+ background-color: rgba(255, 255, 255, 10%);
+}
+
+.Tab-button svg {
+ height: 1.35rem;
+ aspect-ratio: 1;
+}
+
+.Tab-panel {
+ flex: 1;
+ display: flex;
+ flex-wrap: wrap;
+ align-content: flex-start;
+ height: 100%;
+ padding: 0.5rem 1rem;
+ overflow: auto;
+}
+
+.Option {
+ text-align: start;
+ max-width: 100%;
+}
+
+.Input {
+ display: flex;
+ gap: 0.5rem;
+}
+
+.Input > label {
+ flex: 1;
+ display: flex;
+}
+
+.Image-select > input {
+ position: absolute;
+ opacity: 0;
+ width: 0;
+ height: 0;
+}
+
+.Image-select > input:checked + img {
+ outline: 0.25rem solid var(--foreground-color-a);
+}
+
+.Image-select > img {
+ width: 100%;
+ height: 100%;
+ border-radius: 0.5rem;
+ cursor: pointer;
+}
\ No newline at end of file
diff --git a/src/components/task-bar/menus/HomeMenu.jsx b/src/components/task-bar/menus/HomeMenu.jsx
index 0c56f8d..f372ae2 100644
--- a/src/components/task-bar/menus/HomeMenu.jsx
+++ b/src/components/task-bar/menus/HomeMenu.jsx
@@ -50,7 +50,10 @@ export function HomeMenu({ active, setActive, search }) {
-