A powerful HSL-based color picker for Neovim with visual grid navigation, multi-language support, and real-time preview
Features • Installation • Quick Start • Configuration • Keymaps • API
|
|
|
Neovim 0.9+ (0.11+ recommended) |
nvim-float (UI framework) |
termguicolors enabled |
{
"mikevskater/nvim-colorpicker",
dependencies = { "mikevskater/nvim-float" },
cmd = { "ColorPicker", "ColorPickerAtCursor", "ColorPickerMini" },
keys = {
{ "<leader>cp", "<Plug>(colorpicker)", desc = "Color Picker" },
{ "<leader>cc", "<Plug>(colorpicker-at-cursor)", desc = "Pick at Cursor" },
{ "<leader>cm", "<Plug>(colorpicker-mini)", desc = "Mini Picker" },
{ "<leader>ch", "<Plug>(colorpicker-highlight-toggle)", desc = "Toggle Highlighting" },
},
opts = {
alpha_enabled = true,
presets = { "web", "tailwind" },
highlight = {
enable = true,
filetypes = { "css", "scss", "html" },
},
},
}Other Package Managers
packer.nvim
use {
"mikevskater/nvim-colorpicker",
requires = { "mikevskater/nvim-float" },
config = function()
require("nvim-colorpicker").setup()
end,
}vim-plug
Plug 'mikevskater/nvim-float'
Plug 'mikevskater/nvim-colorpicker'
" After plug#end():
lua require('nvim-colorpicker').setup()mini.deps
add({ source = "mikevskater/nvim-float" })
add({ source = "mikevskater/nvim-colorpicker" })Health Check
After installation, verify everything is working:
:checkhealth nvim-colorpicker|
Setup require("nvim-colorpicker").setup()
-- Recommended keymaps
vim.keymap.set("n", "<leader>cp",
"<cmd>ColorPicker<cr>")
vim.keymap.set("n", "<leader>cc",
"<cmd>ColorPickerAtCursor<cr>") |
Pick Colors " Open full picker
:ColorPicker
" Pick at cursor
:ColorPickerAtCursor
" Mini picker
:ColorPickerMini |
Navigate |
Default Configuration
require("nvim-colorpicker").setup({
-- Default color output format: "hex", "rgb", "hsl", "hsv"
default_format = "hex",
-- Hex color case: "upper" or "lower"
hex_case = "upper",
-- Enable alpha channel editing by default
alpha_enabled = false,
-- Number of recent colors to track in history
recent_colors_count = 10,
-- Preset palettes to include: {"web", "material", "tailwind"}
presets = {},
-- Auto-detect movement keys from global Neovim keymaps
-- Useful for Colemak, Dvorak, and other keyboard layouts
inherit_movement_keys = true,
-- Inline color highlighting configuration
highlight = {
enable = false,
filetypes = "*",
exclude_filetypes = {
"lazy", "mason", "help", "TelescopePrompt",
"nvim-float", "nvim-float-form", "nvim-float-interactive",
"nvim-colorpicker-grid", "nvim-colorpicker-info",
},
mode = "background",
swatch_char = "■",
},
-- Keymap configuration
keymaps = {
nav_left = "h", nav_right = "l",
nav_up = "k", nav_down = "j",
sat_up = "K", sat_down = "J",
step_down = "-", step_up = { "+", "=" },
reset = "r", hex_input = "#",
apply = "<CR>", cancel = { "q", "<Esc>" },
help = "?", cycle_mode = "m", cycle_format = "f",
alpha_up = "A", alpha_down = "a",
focus_next = "<Tab>", focus_prev = "<S-Tab>",
},
})| Option | Type | Default | Description |
|---|---|---|---|
default_format |
string | "hex" |
Output format: hex, rgb, hsl, hsv |
hex_case |
string | "upper" |
Hex case: upper or lower |
alpha_enabled |
boolean | false |
Enable alpha channel editing |
recent_colors_count |
number | 10 |
Colors to track in history |
presets |
string[] | {} |
Palettes: web, material, tailwind |
inherit_movement_keys |
boolean | true |
Auto-detect keyboard layout |
highlight.enable |
boolean | false |
Enable auto-highlighting |
highlight.filetypes |
string/table | "*" |
Filetypes to highlight |
highlight.mode |
string | "background" |
background, foreground, virtualtext |
Example: Web Development Setup
require("nvim-colorpicker").setup({
alpha_enabled = true,
presets = { "web", "tailwind" },
highlight = {
enable = true,
filetypes = { "css", "scss", "html", "vue", "svelte", "jsx", "tsx" },
mode = "background",
},
})Example: Custom Color Patterns
require("nvim-colorpicker").setup({
custom_patterns = {
cpp = {
{
pattern = "MyColor%s*%(%s*%d+%s*,%s*%d+%s*,%s*%d+%s*%)",
format = "my_color_rgb",
priority = 100,
parse = function(match)
local r, g, b = match:match("MyColor%s*%(%s*(%d+)%s*,%s*(%d+)%s*,%s*(%d+)%s*%)")
if r and g and b then
return string.format("#%02X%02X%02X", tonumber(r), tonumber(g), tonumber(b))
end
end,
format_color = function(hex, alpha)
local r = tonumber(hex:sub(2, 3), 16)
local g = tonumber(hex:sub(4, 5), 16)
local b = tonumber(hex:sub(6, 7), 16)
return string.format("MyColor(%d, %d, %d)", r, g, b)
end,
},
},
},
})| Command | Description |
|---|---|
:ColorPicker [color] |
Open full color picker |
:ColorPickerAtCursor |
Detect and replace color at cursor |
:ColorPickerMini [color] |
Open compact inline picker |
:ColorPickerMiniAtCursor |
Mini picker at cursor |
:ColorPickerMiniSlider [color] |
Open mini picker in slider mode |
:ColorPickerMiniSliderAtCursor |
Slider mode at cursor |
| Command | Description |
|---|---|
:ColorConvert [format] |
Convert color at cursor (hex, rgb, hsl, hsv) |
:ColorYank [format] |
Copy color at cursor to clipboard |
:ColorPaste |
Paste color from clipboard |
| Command | Description |
|---|---|
:ColorHighlight |
Toggle highlighting in current buffer |
:ColorHighlight on/off |
Enable/disable highlighting |
:ColorHighlight auto |
Enable auto-highlighting for configured filetypes |
:ColorHighlight background/foreground/virtualtext |
Set highlight mode |
| Command | Description |
|---|---|
:ColorHistory [count] |
Display recent colors |
:ColorSearch <query> |
Search presets by color name |
:ColorPickerTest |
Run built-in test suite |
Plug Mappings
| Plug Mapping | Description |
|---|---|
<Plug>(colorpicker) |
Open full color picker |
<Plug>(colorpicker-at-cursor) |
Pick and replace color at cursor |
<Plug>(colorpicker-mini) |
Open mini color picker |
<Plug>(colorpicker-mini-at-cursor) |
Mini picker at cursor |
<Plug>(colorpicker-slider) |
Open picker in slider mode |
<Plug>(colorpicker-slider-at-cursor) |
Slider mode at cursor |
<Plug>(colorpicker-convert-hex) |
Convert to hex |
<Plug>(colorpicker-convert-rgb) |
Convert to rgb |
<Plug>(colorpicker-convert-hsl) |
Convert to hsl |
<Plug>(colorpicker-highlight-toggle) |
Toggle buffer highlighting |
vim.keymap.set("n", "<leader>cp", "<Plug>(colorpicker)")
vim.keymap.set("n", "<leader>cc", "<Plug>(colorpicker-at-cursor)")Grid Navigation
| Key | Action |
|---|---|
h / l |
Adjust hue (left/right) |
j / k |
Adjust lightness (down/up) |
J / K |
Adjust saturation (less/more) |
- / + |
Decrease/increase step multiplier |
[count] |
Use count prefix: 10h, 50k |
Color Mode & Format
| Key | Action |
|---|---|
m |
Cycle mode: HEX → HSL → RGB → HSV → CMYK |
f |
Toggle format: standard/decimal |
o |
Cycle output format (language-aware) |
Actions
| Key | Action |
|---|---|
# |
Enter hex color manually |
r |
Reset to original color |
Enter |
Apply and close |
q / Esc |
Cancel and close |
? |
Show help |
Tab Navigation (Full Picker)
| Key | Action |
|---|---|
g1 |
Info tab (sliders) |
g2 |
History tab |
g3 |
Presets tab |
Tab / S-Tab |
Focus next/previous panel |
| Format | Pattern | Example |
|---|---|---|
| HEX (6-digit) | #RRGGBB |
#FF5500 |
| HEX (3-digit) | #RGB |
#F50 |
| HEX (8-digit) | #RRGGBBAA |
#FF550080 |
| RGB | rgb(r, g, b) |
rgb(255, 85, 0) |
| RGBA | rgba(r, g, b, a) |
rgba(255, 85, 0, 0.5) |
| HSL | hsl(h, s%, l%) |
hsl(20, 100%, 50%) |
| HSLA | hsla(h, s%, l%, a) |
hsla(20, 100%, 50%, 0.5) |
| Vim highlight | guifg=#RRGGBB |
guifg=#FF5500 |
Supported Languages
| Language | Formats Detected |
|---|---|
| CSS/SCSS/LESS | hex, rgb(), rgba(), hsl(), hsla(), hwb(), lab(), lch(), oklch() |
| JavaScript/TypeScript | hex, rgb(), hsl(), 0xRRGGBB |
| Go | color.RGBA{r,g,b,a}, color.NRGBA{}, {r,g,b,a}, 0xRRGGBB, 0xAARRGGBB |
| C++/Qt | QColor("#hex"), QColor(r,g,b), QColor::fromRgbF(), {r,g,b,a}, {0.5f,0.3f,0.1f}, 0xRRGGBB |
| Rust | Color::rgb(), Color::rgba(), Color::srgb(), Srgba::new(), hex!(), 0xRRGGBB |
| Kotlin/Android | Color(0xAARRGGBB), Color.parseColor(), 0xAARRGGBB |
| Swift/SwiftUI | Color(red:green:blue:), UIColor(), NSColor(), #colorLiteral() |
| Dart/Flutter | Color(0xAARRGGBB), Color.fromARGB(), Color.fromRGBO(), Colors.name |
| C#/Unity | Color(r,g,b,a), Color32(r,g,b,a), new Color(), Color.name |
| Python | (r,g,b), (r,g,b,a), pygame.Color(), hex strings |
| Lua/Love2D | {r,g,b}, {r,g,b,a}, love.graphics colors |
| GLSL/HLSL/Metal | vec3(), vec4(), float3(), float4() |
Multi-Language Detection Demo
The demo shows:
- Detecting and editing
color.RGBA{}in Go - Detecting and editing
QColor()in C++ - Detecting and editing float struct
{0.384f, 0.000f, 0.933f}in C++ - Detecting and editing
Color::srgb()in Rust
Output Format Cycling Demo
The demo shows:
- Opening the picker on a Go
color.RGBA{}color - Pressing
oto cycle through available formats - Selecting a different output format before applying
- The color is replaced using the selected format
local colorpicker = require("nvim-colorpicker")Main Functions
| Function | Description |
|---|---|
colorpicker.setup(opts) |
Initialize with configuration |
colorpicker.pick(opts) |
Open picker with options |
colorpicker.pick_at_cursor() |
Pick color at cursor |
colorpicker.pick_mini(opts) |
Open mini picker |
colorpicker.pick_mini_at_cursor() |
Mini picker at cursor |
colorpicker.pick_mini_slider(opts) |
Open slider mode |
colorpicker.get_color() |
Get current color in open picker |
colorpicker.set_color(new, original) |
Set color in open picker |
colorpicker.is_open() |
Check if picker is open |
colorpicker.is_mini_open() |
Check if mini picker is open |
Pick Options
colorpicker.pick({
color = "#ff5500",
alpha_enabled = true,
target_filetype = "go",
original_format = "color_rgba",
on_select = function(result)
print("Selected: " .. result.color)
print("Raw hex: " .. result.hex)
end,
on_cancel = function()
print("Cancelled")
end,
on_change = function(result)
-- Live preview on every change
end,
})Highlighting
| Function | Description |
|---|---|
colorpicker.toggle_highlight() |
Toggle buffer highlighting |
colorpicker.enable_highlight() |
Enable highlighting |
colorpicker.disable_highlight() |
Disable highlighting |
colorpicker.enable_auto_highlight(patterns) |
Enable for file patterns |
colorpicker.set_highlight_mode(mode) |
Set display mode |
History & Clipboard
| Function | Description |
|---|---|
colorpicker.yank(color?, format?) |
Copy color to clipboard |
colorpicker.paste() |
Paste color from clipboard |
colorpicker.get_recent_colors(count) |
Get recent colors |
colorpicker.add_recent_color(color) |
Add to history |
Utilities
local utils = colorpicker.utils()
local r, g, b = utils.hex_to_rgb("#ff5500")
local hex = utils.rgb_to_hex(255, 85, 0)nvim-colorpicker can be integrated into other plugins using callbacks and custom controls.
Integration Demo
The demo shows SSNS Theme Editor using the colorpicker with custom controls for foreground/background toggle and bold/italic styling.
Basic Integration
colorpicker.pick({
color = initial_color,
title = "Edit Color",
on_change = function(result)
update_preview(result.color)
end,
on_select = function(result)
save_color(result.color)
end,
on_cancel = function()
restore_original()
end,
})Custom Controls
colorpicker.pick({
custom_controls = {
{
id = "target",
type = "select",
label = "Target",
options = { "fg", "bg" },
default = "fg",
key = "B",
on_change = function(new_value, old_value)
-- Handle target switch
end,
},
{
id = "bold",
type = "toggle",
label = "Bold",
default = false,
key = "b",
},
},
on_select = function(result)
local target = result.custom.target
local bold = result.custom.bold
-- Use custom values...
end,
})Control Types: toggle, select, number, text
Full Picker
┌─────────────────────────────────────────────────────────────┐
│ #FF5500 HSL 20° 100% 50% Step: 1x │
├────────────────────────────────┬────────────────────────────┤
│ │ [Info] [History] [Presets]│
│ Color Grid (HSL) │ │
│ ██████████████████████████████ │ H: ████████░░░░ 20° │
│ ██████████████████████████████ │ S: ████████████ 100% │
│ ██████████████x ← cursor██████ │ L: ██████░░░░░░ 50% │
│ ██████████████████████████████ │ A: ████████████ 100% │
│ ██████████████████████████████ │ │
│ │ │
├────────────────────────────────│ │
│───Original────┬────Current──── │ │
│███████████████│███████████████ │ │
└────────────────────────────────┴────────────────────────────┘
Mini Picker
┌─ #FF5500 HSL Step: 1x ────────────────┐
│ │
│ Color Grid (compact) │
│ x │
│ │
│ │
├──────Original──────┬──────Current───────┤
│████████████████████│████████████████████│
└─────────────────────────────────────────┘
Slider Mode
┌─ #FF5500 HSL Step: 1x ────────────────┐
│ │
│ H: ████████░░░░ 20° │
│ S: ████████████ 100% │
│ L: ██████░░░░░░ 50% │
│ │
├──────Original──────┬──────Current───────┤
│████████████████████│████████████████████│
└─────────────────────────────────────────┘
Colors not displaying properly?
Ensure termguicolors is enabled:
vim.opt.termguicolors = trueCustom keymaps not working?
If using custom navigation keys, disable auto-detection:
require("nvim-colorpicker").setup({
inherit_movement_keys = false,
keymaps = { ... },
})Highlighting appears in wrong buffers?
Refine your exclude list:
highlight = {
exclude_filetypes = {
"lazy", "mason", "help", "TelescopePrompt",
"NvimTree", "neo-tree", "dashboard", "alpha",
},
}How do I run tests?
:ColorPickerTest " Show results in UI
:ColorPickerTest run " Print to console
:ColorPickerTest last " Show previous resultsContributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Found a bug or have a feature request? Please open an issue on GitHub Issues.
|
When opening an issue, please include:
|








