-
Notifications
You must be signed in to change notification settings - Fork 0
Custom Themes
alsi-lawr edited this page Jul 11, 2026
·
1 revision
Set theme = "custom" to start with seven empty semantic category tables. configure_palette must populate the roles your theme needs.
require("neotheme").setup({
theme = "custom",
configure_palette = function(palette)
palette.surface.base = "#181818"
palette.text.primary = "#e4e4e4"
end,
})
vim.cmd.colorscheme("neotheme")Partial palettes load, but Neotheme emits one warning containing every missing semantic path. A complete custom theme avoids the warning and gives every highlight a defined color.
The example below deliberately reuses a compact color set while supplying every semantic role:
local c = {
deepest = "#0e0e0e",
dark = "#161616",
base = "#1d1d1d",
raised = "#262626",
selected = "#3c3935",
border = "#4a4743",
muted = "#635d54",
text = "#e4dfd7",
bright = "#f4eee5",
strong = "#fff8ef",
red = "#e06b63",
yellow = "#e8c05b",
green = "#93c476",
blue = "#9eb1d1",
teal = "#9daf9e",
purple = "#ab9bc9",
}
local custom = {
surface = {
deepest = c.deepest,
dark = c.dark,
base = c.base,
raised = c.raised,
selected = c.selected,
border = c.border,
muted = c.muted,
addition = "#29332e",
error = "#a6504c",
},
text = {
primary = c.text,
bright = c.bright,
strong = c.strong,
muted = c.teal,
on_accent = c.deepest,
on_error = c.strong,
},
syntax = {
comment = "#bf8a52",
string = c.green,
keyword = c.yellow,
function_name = c.blue,
type = c.teal,
property = "#8997a3",
literal = c.purple,
operator = c.yellow,
punctuation = c.bright,
regexp = c.red,
special = c.red,
attribute = c.teal,
tag = c.blue,
},
diagnostic = {
error = c.red,
warning = c.yellow,
information = c.blue,
hint = c.purple,
success = c.green,
},
markup = {
heading_1 = c.yellow,
heading_2 = c.blue,
heading_3 = c.green,
heading_4 = c.purple,
heading_5 = c.teal,
heading_6 = "#bf8a52",
quote = "#bf8a52",
math = c.purple,
link = c.blue,
link_label = c.yellow,
raw = c.green,
list = c.yellow,
checked = c.green,
unchecked = c.teal,
},
version_control = {
added = c.green,
changed = c.yellow,
removed = c.red,
ignored = c.muted,
conflict = "#ec7c72",
},
ui = {
accent = c.yellow,
cursor = c.yellow,
directory = c.blue,
search = c.yellow,
current_search = c.strong,
match = c.purple,
focus = c.strong,
},
}
require("neotheme").setup({
theme = "custom",
configure_palette = function(palette)
for category, roles in pairs(custom) do
for role, color in pairs(roles) do
palette[category][role] = color
end
end
end,
})
vim.cmd.colorscheme("neotheme")Neotheme sets background to dark for theme = "custom". If your custom palette is light, set the option after loading the colorscheme:
vim.cmd.colorscheme("neotheme")
vim.o.background = "light"This is separate from palette validation and does not alter any custom colors.
Custom palettes follow the same validation rules as built-in customization:
- Unknown categories fail.
- Unknown fields fail.
- Non-string or non-
#RRGGBBvalues fail. - A non-
nilconfigurator return value fails. - Missing fields produce one warning that lists the missing paths.
See Palette Customization for a description of every role.