Theme
SomeWM's appearance is fully customizable through the beautiful module. In this tutorial, we'll create a custom theme from scratch.
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")
-- Later, anywhere in your config:
print(beautiful.bg_normal) -- "#282828"
print(beautiful.font) -- "sans 10"
Creating Your Theme Directory
First, create a directory for your theme:
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 and see your changes!
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
This makes it easy to tweak your entire color scheme by changing values in one place.
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
The simplest way to set a 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!
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