diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 21a05fe4c..6172bac74 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -355,6 +355,9 @@ Makefile @thiagokokada
/modules/programs/wezterm.nix @blmhemu
/tests/modules/programs/wezterm @blmhemu
+/modules/programs/wofi.nix @christoph-heiss
+/tests/modules/programs/wofi @christoph-heiss
+
/modules/programs/xmobar.nix @t4ccer
/tests/modules/programs/xmobar @t4ccer
diff --git a/modules/modules.nix b/modules/modules.nix
index 743bcf6d2..93238ce10 100644
--- a/modules/modules.nix
+++ b/modules/modules.nix
@@ -197,6 +197,7 @@ let
./programs/waybar.nix
./programs/wezterm.nix
./programs/wlogout.nix
+ ./programs/wofi.nix
./programs/xmobar.nix
./programs/yt-dlp.nix
./programs/z-lua.nix
diff --git a/modules/programs/wofi.nix b/modules/programs/wofi.nix
new file mode 100644
index 000000000..e1e84ba25
--- /dev/null
+++ b/modules/programs/wofi.nix
@@ -0,0 +1,76 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.programs.wofi;
+
+ toConfig = attrs:
+ ''
+ # Generated by Home Manager.
+ '' + generators.toKeyValue { }
+ (filterAttrs (name: value: value != null) attrs);
+in {
+ meta.maintainers = [ maintainers.christoph-heiss ];
+
+ options.programs.wofi = {
+ enable = mkEnableOption
+ "wofi: a launcher/menu program for wlroots based wayland compositors such as sway";
+
+ package = mkPackageOption pkgs "wofi" { };
+
+ settings = mkOption {
+ default = { };
+ type = types.attrs;
+ description = ''
+ Configuration options for wofi. See
+
+ wofi
+ 5
+ .
+ '';
+ example = literalExpression ''
+ {
+ location = "bottom-right";
+ allow_markup = true;
+ width = 250;
+ }
+ '';
+ };
+
+ style = mkOption {
+ default = null;
+ type = types.nullOr types.str;
+ description = ''
+ CSS style for wofi to use as a stylesheet. See
+
+ wofi
+ 7
+ .
+ '';
+ example = ''
+ * {
+ font-family: monospace;
+ }
+
+ window {
+ background-color: #7c818c;
+ }
+ '';
+ };
+ };
+
+ config = mkIf cfg.enable {
+ assertions =
+ [ (hm.assertions.assertPlatform "programs.wofi" pkgs platforms.linux) ];
+
+ home.packages = [ cfg.package ];
+
+ xdg.configFile = mkMerge [
+ (mkIf (cfg.settings != { }) {
+ "wofi/config".text = toConfig cfg.settings;
+ })
+ (mkIf (cfg.style != null) { "wofi/style.css".text = cfg.style; })
+ ];
+ };
+}
diff --git a/tests/default.nix b/tests/default.nix
index 2ccf27d51..c189d14aa 100644
--- a/tests/default.nix
+++ b/tests/default.nix
@@ -167,6 +167,7 @@ import nmt {
./modules/programs/thunderbird
./modules/programs/waybar
./modules/programs/wlogout
+ ./modules/programs/wofi
./modules/programs/xmobar
./modules/programs/yt-dlp
./modules/services/avizo
diff --git a/tests/modules/programs/wofi/basic-configuration.conf b/tests/modules/programs/wofi/basic-configuration.conf
new file mode 100644
index 000000000..0d0a79d0b
--- /dev/null
+++ b/tests/modules/programs/wofi/basic-configuration.conf
@@ -0,0 +1,6 @@
+# Generated by Home Manager.
+drun-print_command=true
+insensitive=true
+show=drun
+xoffset=50
+yoffset=200
diff --git a/tests/modules/programs/wofi/basic-configuration.nix b/tests/modules/programs/wofi/basic-configuration.nix
new file mode 100644
index 000000000..afcb69c77
--- /dev/null
+++ b/tests/modules/programs/wofi/basic-configuration.nix
@@ -0,0 +1,35 @@
+{ pkgs, ... }:
+
+{
+ config = {
+ programs.wofi = {
+ enable = true;
+ package = pkgs.writeScriptBin "dummy-wofi" "";
+ style = ''
+ * {
+ font-family: monospace;
+ }
+ window {
+ background-color: #7c818c;
+ }
+ '';
+ settings = {
+ drun-print_command = true;
+ insensitive = true;
+ show = "drun";
+ xoffset = 50;
+ yoffset = 200;
+ };
+ };
+
+ nmt.script = ''
+ assertFileExists home-files/.config/wofi/config
+ assertFileContent home-files/.config/wofi/config \
+ ${./basic-configuration.conf}
+
+ assertFileExists home-files/.config/wofi/style.css
+ assertFileContent home-files/.config/wofi/style.css \
+ ${./basic-style.css}
+ '';
+ };
+}
diff --git a/tests/modules/programs/wofi/basic-style.css b/tests/modules/programs/wofi/basic-style.css
new file mode 100644
index 000000000..734e537aa
--- /dev/null
+++ b/tests/modules/programs/wofi/basic-style.css
@@ -0,0 +1,6 @@
+* {
+ font-family: monospace;
+}
+window {
+ background-color: #7c818c;
+}
diff --git a/tests/modules/programs/wofi/default.nix b/tests/modules/programs/wofi/default.nix
new file mode 100644
index 000000000..f06667b0f
--- /dev/null
+++ b/tests/modules/programs/wofi/default.nix
@@ -0,0 +1,4 @@
+{
+ wofi-basic-configuration = ./basic-configuration.nix;
+ wofi-empty-configuration = ./empty-configuration.nix;
+}
diff --git a/tests/modules/programs/wofi/empty-configuration.nix b/tests/modules/programs/wofi/empty-configuration.nix
new file mode 100644
index 000000000..b3e4a4f6c
--- /dev/null
+++ b/tests/modules/programs/wofi/empty-configuration.nix
@@ -0,0 +1,15 @@
+{ pkgs, ... }:
+
+{
+ config = {
+ programs.wofi = {
+ enable = true;
+ package = pkgs.writeScriptBin "dummy-wofi" "";
+ };
+
+ nmt.script = ''
+ assertPathNotExists home-files/.config/wofi/config
+ assertPathNotExists home-files/.config/wofi/style.css
+ '';
+ };
+}