GitHub

MELPA Build Status

Batppuccin is an opinionated Emacs port of the Catppuccin color scheme. It aims to follow the official Catppuccin style guide closely while being structured idiomatically for Emacs.

The name is a play on my last name (Batsov) + Catppuccin (cat -> bat). So, that's essentially @bbatsov's take on Catppuccin.1

Why Another Catppuccin Theme?

The official catppuccin/emacs port has some fundamental issues that are hard to fix incrementally:

Architectural Problems

  • Registers a single catppuccin theme and switches flavors via a global variable + reload function. This breaks standard load-theme workflows, theme-switching packages like circadian.el, and any tooling that expects one theme = one entry in custom-theme-load-path. Batppuccin defines four proper themes (batppuccin-mocha, batppuccin-latte, etc.) that work with load-theme out of the box.
  • Loads color definitions from an external file using load-file-name, which is nil in certain load-theme code paths (e.g., when Emacs hasn't marked the theme as safe yet). This causes the theme to fail to load entirely for some users.
  • No semantic color layer, so faces reference raw palette colors directly, which makes it hard to reason about color assignments or adjust them systematically.

I think this is partly because the official Emacs port uses Catppuccin's Whiskers template tool to generate the Elisp from a .tera template. That's great for keeping ports in sync across editors, but it means the generated code doesn't follow Emacs conventions. It doesn't sit well with me.

Style Guide Deviations

  • font-lock-variable-name-face is set to the default text color, making variables indistinguishable from surrounding text. The style guide assigns distinct colors to variables and properties.
  • All outline-* levels use the same blue, so org-mode headings and any outline-based hierarchy look flat. The style guide specifies a rainbow cycle (red, peach, yellow, green, sapphire, lavender).
  • org-block forces a green foreground on all unstyled code inside source blocks, instead of inheriting the default text color.
  • Search match highlighting uses aggressive red backgrounds where the style guide calls for teal.
  • Minibuffer prompt uses a subdued gray (subtext0) instead of a prominent color.

Placeholder Colors in Production

Multiple faces (dired+, diredfl, tree-sitter, whitespace, helm) are set to #ff00ff magenta as a "TODO" placeholder. These show up as literal hot pink in real usage.

Missing Face Coverage

No support for vertico, marginalia, embark, transient, flycheck, doom-modeline, cider, corfu, or several other widely-used packages.

Approach

Batppuccin follows the conventions established in zenburn-emacs and emacs-tokyo-night-theme:

  • One theme file per flavor. Each variant (batppuccin-mocha-theme.el, batppuccin-latte-theme.el, etc.) is a thin wrapper that loads the shared infrastructure and applies its palette, so standard Emacs theme machinery works without any special glue.
  • The shared infrastructure lives in batppuccin.el: color palettes for all four flavors, the face application function, and a defcustom for user color overrides. Adding a new variant means a color alist and a ~10-line wrapper.
  • All 26 canonical Catppuccin colors with exact hex values from the spec, plus derived colors for diff backgrounds, selection, cursor line, and the heading rainbow cycle.
  • Syntax highlighting follows the Catppuccin style guide (mauve for keywords, green for strings, blue for functions, peach for constants, sky for operators, yellow for types, overlay2 for comments, rosewater for the cursor), and so does the editor UI (lavender for active line numbers, teal for search backgrounds, red/green/blue at low opacity for diffs).
  • Broad face coverage out of the box: built-in Emacs faces plus magit, vertico, corfu, marginalia, embark, orderless, consult, transient, flycheck, flymake, cider, company, evil, mu4e, notmuch, doom-modeline, treemacs, web-mode, and more.

Installation

MELPA

Batppuccin is available on MELPA. Assuming you've configured MELPA as a package source:

M-x package-install RET batppuccin RET

Then load any flavor:

(load-theme 'batppuccin-mocha t)

Or with use-package:

(use-package batppuccin
  :ensure t
  :config
  (load-theme 'batppuccin-mocha t))

package-vc-install

(package-vc-install "https://github.com/bbatsov/batppuccin-emacs")
(load-theme 'batppuccin-mocha t)

use-package (with package-vc)

(use-package batppuccin
  :vc (:url "https://github.com/bbatsov/batppuccin-emacs" :rev :newest)
  :config
  (load-theme 'batppuccin-mocha t))

straight.el

(straight-use-package
 '(batppuccin-latte-mocha :host github :repo "bbatsov/batppuccin-emacs"))
(load-theme 'batppuccin-mocha t)

Or with use-package integration.

(use-package batppuccin-mocha
  :straight (:host github :repo "bbatsov/batppuccin-emacs")
  :config (load-theme 'batppuccin-mocha t))

From source

Clone the repo and add it to your load path:

(add-to-list 'custom-theme-load-path "/path/to/batppuccin-emacs")
(load-theme 'batppuccin-mocha t)

Flavors

Flavor Description
batppuccin-mocha The darkest variant
batppuccin-macchiato Dark
batppuccin-frappe Medium-dark
batppuccin-latte Light

Customization

Override any color across all flavors:

(setq batppuccin-override-colors-alist
      '(("bat-base" . "#000000")
        ("bat-text" . "#ffffff")))

The override alist takes precedence over the built-in palette. Color names match the canonical Catppuccin names with a bat- prefix (e.g., bat-rosewater, bat-mauve, bat-surface0).

Appearance options

A handful of booleans and numbers adjust the look without forking. They all take effect on the next load-theme (or M-x batppuccin-reload).

Headings in org, outline, markdown, adoc, asciidoc, shr and info are scaled by default. Turn that off for uniform sizes:

(setq batppuccin-scale-headings nil)

Or keep the scaling but tune how much each level grows:

(setq batppuccin-height-doc-title 1.5   ; document titles (default 1.4)
      batppuccin-height-1 1.4           ; level-1 headings (default 1.3)
      batppuccin-height-2 1.2           ; level-2 headings (default 1.2)
      batppuccin-height-3 1.1)          ; level-3 headings (default 1.1)

Render headings in a proportional font, which reads nicely for prose:

(setq batppuccin-use-variable-pitch t)

Variable-pitch headings, off and on

Comments and docstrings are italic by default. If your font renders italics poorly, turn that off:

(setq batppuccin-italic-comments nil)

Drop the box around the mode line for a flat look:

(setq batppuccin-flat-mode-line t)

Boxed vs flat mode line

After changing any of these options, run M-x batppuccin-reload to apply them without restarting Emacs.

Interactive Commands

  • M-x batppuccin-select - pick a flavor interactively and load it
  • M-x batppuccin-reload - reload the current theme after changing options
  • M-x batppuccin-list-colors - display all palette colors with samples (prefix arg to pick a variant)

Programmatic Access

If you need to reference theme colors in your own configuration, there are a couple of options.

Look up a single color:

(batppuccin-get-color "bat-blue")

Or bind the entire palette as local variables with batppuccin-with-colors:

(batppuccin-with-colors
  (set-face-attribute 'some-face nil :foreground bat-blue))

You can also hook into theme loads with batppuccin-after-load-hook. Each function receives the theme name as its argument:

(add-hook 'batppuccin-after-load-hook
          (lambda (_theme)
            (batppuccin-with-colors
              (set-face-attribute 'my-face nil :foreground bat-teal))))

Automatic Light/Dark Switching

Batppuccin pairs well with packages that switch themes based on the time of day or your OS appearance setting:

  • auto-dark tracks your OS dark/light mode and switches themes to match:
(use-package auto-dark
  :config
  (setq auto-dark-themes '((batppuccin-mocha) (batppuccin-latte)))
  (auto-dark-mode 1))
  • circadian switches on a time-based schedule (e.g. sunrise/sunset):
(use-package circadian
  :config
  (setq circadian-themes '((:sunrise . batppuccin-latte)
                            (:sunset  . batppuccin-mocha)))
  (circadian-setup))

See Automatic Light/Dark Theme Switching for a deeper look at both approaches.

License

GNU General Public License v3.0. See COPYING for details.

Footnotes

  1. Naming is hard, but it should also be fun!

Read the original on github.com ↗