Theme
You will learn
- How
beautifulvariables flow to every widget - How to write and load a theme file
- How to build a swappable color scheme system
- How to set wallpapers and recolor icons
This page retrofits one feature into an existing config. If you would rather build a complete desktop from the ground up, the Awesome From Scratch series covers this topic as part of a thirteen-chapter course.
How Theming Works
All visual styling in SomeWM flows through the beautiful module. When you call beautiful.init() with a theme file, it loads variables like beautiful.bg_normal, beautiful.font, etc. that widgets and other components read to style themselves.
-- In your rc.lua
local beautiful = require("beautiful")
beautiful.init("/path/to/your/theme.lua")
-- Anywhere AFTER init(), including inside required modules:
print(beautiful.bg_normal) -- "#282828"
print(beautiful.font) -- "sans 10"
Order matters: before beautiful.init() runs, every theme variable is nil and reading one produces no error. This includes code that runs inside modules your rc.lua requires, so require widget modules after the beautiful.init() call.
Creating Your Theme Directory
mkdir -p ~/.config/somewm/theme
Theme File
Create ~/.config/somewm/theme/theme.lua:
-- ~/.config/somewm/theme/theme.lua
local gears = require("gears")
local xresources = require("beautiful.xresources")
local dpi = xresources.apply_dpi
local theme = {}
-- Fonts
theme.font = "sans 10"
-- Colors
theme.bg_normal = "#222222"
theme.bg_focus = "#535d6c"
theme.bg_urgent = "#ff0000"
theme.bg_minimize = "#444444"
theme.fg_normal = "#aaaaaa"
theme.fg_focus = "#ffffff"
theme.fg_urgent = "#ffffff"
theme.fg_minimize = "#ffffff"
-- Borders
theme.useless_gap = dpi(4)
theme.border_width = dpi(1)
theme.border_color_normal = "#000000"
theme.border_color_active = "#535d6c"
-- Wallpaper
theme.wallpaper = "/path/to/your/wallpaper.jpg"
return theme
Loading Your Theme
Update your rc.lua to use your new theme:
local beautiful = require("beautiful")
-- Use your custom theme
local config_dir = os.getenv("HOME") .. "/.config/somewm"
beautiful.init(config_dir .. "/theme/theme.lua")
Press Mod4 + Ctrl + r to reload.
Understanding DPI Scaling
The apply_dpi() function scales values based on your screen's DPI. This ensures your theme looks consistent across different displays:
local xresources = require("beautiful.xresources")
local dpi = xresources.apply_dpi
-- These scale with DPI:
theme.useless_gap = dpi(8) -- Gap between windows
theme.border_width = dpi(2) -- Window border thickness
theme.menu_height = dpi(24) -- Menu item height
On a 4K display, dpi(8) might become 16 pixels, while on a 1080p display it stays at 8.
Always use dpi() for sizes that should scale: gaps, borders, padding, icon sizes. Don't use it for things like opacity or color values.
Building a Color Scheme System
Instead of hardcoding colors everywhere, organize them in a table:
local theme = {}
-- Define your color palette
local colors = {
bg = "#282828",
fg = "#ebdbb2",
red = "#cc241d",
green = "#98971a",
yellow = "#d79921",
blue = "#458588",
purple = "#b16286",
aqua = "#689d6a",
orange = "#d65d0e",
grey = "#928374",
}
-- Use colors throughout your theme
theme.bg_normal = colors.bg
theme.fg_normal = colors.fg
theme.bg_urgent = colors.red
theme.border_color_active = colors.green
Supporting Multiple Color Schemes
Take it further by defining multiple palettes:
local colors = {
gruvbox = {
bg = "#282828",
fg = "#ebdbb2",
red = "#cc241d",
green = "#98971a",
yellow = "#d79921",
blue = "#458588",
purple = "#b16286",
orange = "#d65d0e",
},
nord = {
bg = "#2E3440",
fg = "#D8DEE9",
red = "#BF616A",
green = "#A3BE8C",
yellow = "#EBCB8B",
blue = "#8FBCBB",
purple = "#B48EAD",
orange = "#D08770",
},
}
-- Switch schemes by changing this one line
local color_scheme = "gruvbox"
local c = colors[color_scheme]
theme.bg_normal = c.bg
theme.fg_normal = c.fg
-- ... etc
Theme Variable Reference
For a complete list of all theme variables, see the Theme Variables Reference.
The most commonly customized categories include:
- Core colors -
bg_normal,fg_normal,bg_focus, etc. - Window borders -
border_width,border_color_active,useless_gap - Fonts -
font,hotkeys_font,notification_font - Wibar -
wibar_bg,wibar_fg,wibar_height
Setting a Wallpaper
Simple Wallpaper
theme.wallpaper = "/home/user/wallpapers/mountain.jpg"
This is used by the default request::wallpaper handler in your rc.lua.
Per-Screen Wallpapers
For different wallpapers on each screen, modify your rc.lua:
local wallpapers = {
"/home/user/wallpapers/primary.jpg",
"/home/user/wallpapers/secondary.jpg",
}
screen.connect_signal("request::wallpaper", function(s)
gears.wallpaper.maximized(wallpapers[s.index] or wallpapers[1], s, true)
end)
Wallpaper Functions
The gears.wallpaper module offers several options:
-- Fill screen, cropping if needed
gears.wallpaper.maximized("/path/to/wallpaper.jpg", s, true)
-- Fit to screen, may show background color
gears.wallpaper.fit("/path/to/wallpaper.jpg", s, "#000000")
-- Tile a pattern
gears.wallpaper.tiled("/path/to/pattern.png", s)
-- Solid color
gears.wallpaper.set("#282828")
Recoloring Icons
Many themes use white or black icons and recolor them to match the theme. Use gears.color.recolor_image:
local gears = require("gears")
local recolor = gears.color.recolor_image
-- Original icon is white, recolor to match theme
theme.layout_tile = recolor("/path/to/tile.png", colors.fg)
theme.layout_floating = recolor("/path/to/floating.png", colors.fg)
This is especially useful for layout icons in the wibar.
Customizing Specific Widgets
Taglist
theme.taglist_bg_focus = colors.grey
theme.taglist_bg_occupied = nil -- use default
theme.taglist_bg_empty = colors.bg
theme.taglist_bg_urgent = colors.red
theme.taglist_fg_focus = colors.yellow
theme.taglist_fg_occupied = colors.orange
theme.taglist_fg_empty = colors.fg
Tasklist
theme.tasklist_bg_focus = colors.grey
theme.tasklist_fg_focus = colors.fg
theme.tasklist_disable_icon = true -- text-only tasklist
Notifications
theme.notification_bg = colors.bg
theme.notification_fg = colors.fg
theme.notification_border_color = colors.orange
theme.notification_border_width = dpi(2)
theme.notification_icon_size = dpi(64)
Hotkeys Popup
theme.hotkeys_bg = colors.bg
theme.hotkeys_fg = colors.fg
theme.hotkeys_border_color = colors.yellow
theme.hotkeys_border_width = dpi(2)
theme.hotkeys_modifiers_fg = colors.orange
theme.hotkeys_label_bg = colors.green
theme.hotkeys_label_fg = colors.fg
Complete Example Theme
Here's a complete theme file bringing everything together:
-- ~/.config/somewm/theme/theme.lua
local gears = require("gears")
local theme_assets = require("beautiful.theme_assets")
local xresources = require("beautiful.xresources")
local dpi = xresources.apply_dpi
local recolor = gears.color.recolor_image
local theme = {}
-- Get path to default theme for fallback icons
local themes_path = gears.filesystem.get_themes_dir()
--------------------------------------------------
-- Color Scheme
--------------------------------------------------
local colors = {
bg = "#282828",
fg = "#ebdbb2",
grey = "#928374",
grey2 = "#3c3836",
red = "#fb4934",
green = "#b8bb26",
yellow = "#fabd2f",
blue = "#83a598",
purple = "#d3869b",
orange = "#fe8019",
}
--------------------------------------------------
-- Core
--------------------------------------------------
theme.font = "JetBrainsMono Nerd Font 10"
theme.bg_normal = colors.bg
theme.bg_focus = colors.grey2
theme.bg_urgent = colors.red
theme.bg_minimize = colors.grey
theme.fg_normal = colors.fg
theme.fg_focus = "#ffffff"
theme.fg_urgent = "#ffffff"
theme.fg_minimize = colors.fg
--------------------------------------------------
-- Borders & Gaps
--------------------------------------------------
theme.useless_gap = dpi(8)
theme.border_width = dpi(2)
theme.border_color_normal = colors.bg
theme.border_color_active = colors.green
theme.border_color_marked = colors.red
--------------------------------------------------
-- Wibar
--------------------------------------------------
theme.wibar_bg = colors.bg
theme.wibar_fg = colors.fg
theme.wibar_height = dpi(32)
--------------------------------------------------
-- Taglist
--------------------------------------------------
theme.taglist_bg_focus = colors.grey
theme.taglist_bg_urgent = colors.red
theme.taglist_fg_focus = colors.yellow
theme.taglist_fg_occupied = colors.orange
theme.taglist_fg_empty = colors.fg
--------------------------------------------------
-- Notifications
--------------------------------------------------
theme.notification_bg = colors.bg
theme.notification_fg = colors.fg
theme.notification_border_color = colors.orange
theme.notification_border_width = dpi(2)
--------------------------------------------------
-- Hotkeys Popup
--------------------------------------------------
theme.hotkeys_bg = colors.bg
theme.hotkeys_border_color = colors.yellow
theme.hotkeys_border_width = dpi(2)
theme.hotkeys_modifiers_fg = colors.orange
theme.hotkeys_label_bg = colors.green
--------------------------------------------------
-- Layout Icons (recolored)
--------------------------------------------------
theme.layout_tile = recolor(themes_path .. "default/layouts/tilew.png", colors.fg)
theme.layout_tileleft = recolor(themes_path .. "default/layouts/tileleftw.png", colors.fg)
theme.layout_floating = recolor(themes_path .. "default/layouts/floatingw.png", colors.fg)
theme.layout_max = recolor(themes_path .. "default/layouts/maxw.png", colors.fg)
theme.layout_fair = recolor(themes_path .. "default/layouts/fairvw.png", colors.fg)
--------------------------------------------------
-- Menu
--------------------------------------------------
theme.menu_height = dpi(20)
theme.menu_width = dpi(140)
-- Generate awesome icon
theme.awesome_icon = theme_assets.awesome_icon(
theme.menu_height, theme.bg_focus, theme.fg_focus
)
--------------------------------------------------
-- Wallpaper
--------------------------------------------------
theme.wallpaper = os.getenv("HOME") .. "/wallpapers/gruvbox.jpg"
return theme
Troubleshooting
Theme not loading
Check the path in your beautiful.init() call:
-- Make sure the path is correct
beautiful.init(os.getenv("HOME") .. "/.config/somewm/theme/theme.lua")
Colors not applying
Make sure your theme file returns the theme table:
local theme = {}
-- ... your theme settings ...
return theme -- Don't forget this!
Also check when your code reads the theme. A module required before beautiful.init() sees nil for every theme variable, silently. Values copied at require time (like bg = beautiful.bg_normal at the top of a widget module) stay nil even after init() runs later. Move widget requires below beautiful.init() in your rc.lua.
Icons not showing
If using custom icon paths, verify the files exist:
ls ~/.config/somewm/theme/icons/
For layout icons, you can use the default theme's icons as a starting point:
local themes_path = gears.filesystem.get_themes_dir()
theme.layout_tile = themes_path .. "default/layouts/tilew.png"
Next Steps
- Theme Variables Reference - Complete list of all theme variables
- Widgets - Create custom widgets
- beautiful (AwesomeWM docs) - Upstream API reference