popwin turns the buffers Emacs opens without asking into popups you can dismiss
Popup Window Manager for Emacs
At a glance
- What is it?
- popwin is a popup window manager for Emacs, and it exists to deal with the buffers Emacs opens on your behalf: the help buffer, the completion list, the compilation output. Those buffers appear in a window that splits your layout and then stays there, and popwin shows them in a popup instead, which you dismiss with a single keystroke.
- Who is it for?
- Adopt popwin if the windows that Emacs opens by itself are a recurring irritation, since the package turns them into dismissible popups without changing how any command works. Skip it if you use a modern completion UI or a window management package that already handles those buffers.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Yes. The repository last received commits 126 days ago.
- What is it written in?
- Mainly Emacs Lisp, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The complaint that started the package
popwin is described as a popup window manager for Emacs which makes you free from the hell of annoying buffers such like *Help*, *Completions*, *compilation*, and so on.
The example given is the one everybody recognises. When you complete file names during find-file, the *Completions* buffer appears in a newly splitted window. The documentation puts the question well: you might understand the necessity of the window, but you may wonder why the window still remains after completion.
That question is the whole problem. Emacs has a long history of using buffers for transient output, and the standard behaviour is to display them in a window that splits your layout. The split is often useful, because you want to read the output while you work. But the buffer is not cleaned up afterwards, so the window stays, taking up space and changing the window arrangement you had set up carefully.
popwin resolves those problems. Windows of such temporary buffers will be shown as a popup window, and you can close them smoothly by typing C-g at any time.
C-g is the right choice of key. It is the standard Emacs interrupt, so it is muscle memory that every Emacs user already has, and pressing it does not cancel what you were working on. A popup that vanishes on the same key that cancels a half-typed command is a popup that costs nothing to dismiss.
There is a second dismissal route, which the basic usage section mentions: selecting another window. So the popup disappears either when you press C-g or when you go somewhere else, which means it never becomes the thing you are stuck with.
The package is Emacs Lisp, published on MELPA and on MELPA Stable, with a continuous integration badge. The default branch is master and the last push was on 2026-06-19.
Installing it
The recommended route is MELPA, and the package is available there.
The manual route is described too. Install popwin.el into your load-path directory, and if you have install-elisp or auto-install you may install it like this:
;; install-elisp
(install-elisp "https://raw.github.com/m2ym/popwin-el/master/popwin.el")
;; auto-install
(auto-install-from-url "https://raw.github.com/m2ym/popwin-el/master/popwin.el")Those two calls are the classic ways of adding a single Emacs Lisp file from a URL, and they are worth noting because they work with any package that ships as one .el file, which popwin does.
Then you add the following code into your .emacs:
(require 'popwin)
(popwin-mode 1)That is the whole configuration. The require loads the package and the mode call turns it on.
The mode is a minor mode, which is the right shape for this. It is not a global mode that changes how Emacs works, it is a mode you enable, and because it is a mode you can toggle it, bind it, or set it per directory with a file-local variable if you want it only in some projects.
The supported version claim is that popwin is tested under GNU Emacs 22 or later. That is an unusually old baseline and it tells you something about the code: it is written in a conservative style that has kept working across a very long span of Emacs versions.
The releases are 1.0.2 from 2020-09-08 and v1.0.1 from 2020-01-22, and there is no release newer than those even though the repository was pushed to in June 2026. A stable Emacs package that is essentially feature-complete is exactly the kind of thing that stops getting new versions, and the maintenance work on such a package tends to be compatibility fixes rather than new features.
The configuration variable and how it matches buffers
The configuration is one variable, and the documentation describes its structure precisely enough to be usable.
popwin:special-display-config is a list of CONFIG. A CONFIG may be a form of (PATTERN . KEYWORDS), where PATTERN is a pattern of specifying a buffer, and KEYWORDS is a list of a pair of key and value.
So the shape is a list of entries, each of which pairs a way of identifying a buffer with a set of options for how to display it. That is a small, regular data structure, which is the right design for a value you are expected to edit by hand in your init file or through the customize interface.
The PATTERN can be one of three things. It is a buffer name, it is a symbol specifying a major-mode, or it is a predicate function which takes the buffer. If CONFIG is a string or a symbol, PATTERN will be CONFIG and KEYWORDS will be empty.
That last rule is what makes the common case short. If you only want to say which buffers should pop up and not care how, you push the name and stop. The three kinds of pattern cover three different needs.
A buffer name is the most precise: it matches one specific buffer, and it is what you use for the odd buffer that you want popped up but whose mode you do not want to affect.
A major-mode symbol is the most useful: matching a mode catches every buffer of that kind, including the ones you have never seen because they are created by a command you do not know about. Matching compilation-mode is the way to say that every compilation output should pop up.
A predicate function is the most flexible: you get the buffer and you decide. That is how you catch a buffer by something other than its name, such as its content or its size.
The :regexp keyword is the modifier for the name case. If the value is non-nil, PATTERN will be used as a regexp to matching buffer. So a name pattern can be a regular expression rather than a literal, which is how you match a family of buffers such as everything that starts with a given prefix.
The keyword list
The available keywords are listed one at a time, and each one controls a specific aspect of the popup.
The size keywords are :width and :height. If no size is specified, popwin:popup-window-width or popwin:popup-window-height will be used. So there is a global default for the popup size and a per-buffer override, which is the arrangement that makes a global variable and a per-case list work together.
The position keyword is :position, and the value must be one of (left top right bottom). The popup window will be shown at the position of the frame. If no position is specified, popwin:popup-window-position will be used.
The position matters more than it sounds. A completion list at the bottom of the frame is close to where you are typing, a help buffer on the right is out of the way of the cursor, and a large output like a compilation log is better on the left where it does not cover what you are working on. Making the position per-pattern rather than global is what lets the package serve both cases.
The :noselect keyword controls focus. If the value is non-nil, the popup window will not be selected when it is shown. That is the setting you want for anything that interrupts, because you do not want the completion list stealing your cursor mid-word.
The :dedicated keyword is the most subtle. If the value is non-nil, the popup window will be dedicated to the original popup buffer. In this case, when another buffer is selected in the popup window, the popup window will be closed immediately and the selected buffer will be shown on the previously selected window.
So the popup gives its buffer back to wherever it came from as soon as you select something else. That is the behaviour that makes a popup feel like a temporary overlay rather than a new permanent window.
Then :stick, where a non-nil value means the popup window will be stuck when it is shown, and :tail, where a non-nil value means the popup window will show the last contents.
The stick keyword is the one that changes the character of the popup. A stuck popup does not go away when you move on, so it is what you use for something you want to keep visible while you work, such as a compilation log you are watching. It is the opposite of the default dismissal behaviour, and having it as a per-buffer option means you can have both kinds in the same configuration.
Examples and the keymap
The examples section is a list of configuration snippets, and reading them is the fastest way to understand what the configuration is for.
The simplest entries are strings pushed straight onto the list. The shell output case is one:
;; M-x anything
(setq anything-samewindow nil)
(push '("*anything*" :height 20) popwin:special-display-config)
;; M-x dired-jump-other-window
(push '(dired-mode :position top) popwin:special-display-config)
;; M-!
(push "*Shell Command Output*" popwin:special-display-config)And the slime example shows a package that needs several different behaviours at once:
(push "*slime-apropos*" popwin:special-display-config)
(push "*slime-macroexpansion*" popwin:special-display-config)
(push "*slime-description*" popwin:special-display-config)
(push '("*slime-compilation*" :noselect t) popwin:special-display-config)
(push "*slime-xref*" popwin:special-display-config)
(push '(sldb-mode :stick t) popwin:special-display-config)
(push 'slime-repl-mode popwin:special-display-config)
(push 'slime-connection-list-mode popwin:special-display-config)That block is instructive because it mixes the kinds of pattern in one package. Several are plain buffer names for the apropos, macroexpansion and description buffers. The compilation buffer gets the:noselect option, since the compilation output appears as you type a command and you do not want the cursor moved. And the sldb-mode entry gets:stick, because the debugger prompt is something you interact with across several steps and you want it to stay.
So a single package ends up with three different popup behaviours, which is exactly what the structure is designed for.
The undo-tree example is worth noting too, because it combines keywords: a name pattern with:width set to 0.3 and:position set to right. A width of 0.3 means a fraction of the frame rather than a character count, so the popup scales with the window size.
Then there is the keymap. popwin provides a default keymap named popwin:keymap, and you can use it like this:
(global-set-key (kbd "C-z") popwin:keymap)The bindings are:
| Key | Command |
|--------+---------------------------------------|
| b | popwin:popup-buffer |
| l | popwin:popup-last-buffer |
| o | popwin:display-buffer |
| C-b | popwin:switch-to-last-buffer |
| C-p | popwin:original-pop-to-last-buffer |
| C-o | popwin:original-display-last-buffer |
| SPC | popwin:select-popup-window |
| s | popwin:stick-popup-window |
| 0 | popwin:close-popup-window |
| f, C-f | popwin:find-file |
| e | popwin:messages |
| C-u | popwin:universal-display |
| 1 | popwin:one-window |The pattern is that there is a pair of commands for most actions, one that operates on the popup and one that operates on the last buffer. The b and l bindings pop the current buffer and pop the last one, the o binding displays a buffer, and the C-b and C-p bindings switch to the last buffer or pop to it from wherever you were. The 0 binding closes the popup window, the 1 binding goes back to a single window, and SPC selects the popup window.
Binding it to C-z is the documented example, although note that C-z suspends Emacs by default in a standard configuration. The popwin:find-file and popwin:messages bindings let you trigger the package's behaviour from a key rather than waiting for a buffer to appear, which is the other half of how you use it.
Universal display, and how the package is built
There is a second configuration variable for the case where you want a popup for a specific buffer at the time rather than by rule.
popwin:universal-display-config is a special alternative value of popwin:special-display-config, which will be used when executing a command with an M-x popwin:universal-display prefix. If you want to show a specific buffer in a popup window at the time, for example, you can do it with the universal display command followed by the buffer selection.
The idea is that you get a command prefix, and then whatever you do next is displayed in a popup instead of in the usual way. So you can prefix any display command with it and get a popup for that one instance, without adding a rule to the configuration list.
That is a good design, because the rules list is for the buffers you always want popped up, and the universal command is for the ones you occasionally want popped up. It is the difference between a configuration and a mode.
Now the build side, which is visible in the repository. The top-level entries are the package itself as popwin.el, a Makefile, an Eask file, and directories for tests, for etc and for miscellaneous files.
Eask is the build and package management system for Emacs Lisp, and the Makefile wraps it. The Makefile defines EMACS and EASK as overridable variables and lists the targets as clean, checkdoc, lint, package, install, compile and test. The ci target chains clean, package, install and compile.
checkdoc is the one target worth singling out, because it is the Emacs-specific documentation checker. It verifies that every function has a docstring in the expected format and that the docstring's first line is a complete sentence ending with a period. That is why the documentation in the README looks the way it does, with each keyword having a paragraph that begins with a single capitalised sentence.
The continuous integration badge in the README points at a workflow named test, and the repository has a test/ directory, so the package has automated tests alongside the docstring checks.
The one thing to note about maintenance is the release history. The tags stop in 2020 while the repository is still being pushed to, so the work since then has been compatibility and documentation fixes rather than features. For an Emacs package whose entire behaviour is a window display convention, that is an entirely reasonable place to be.
Editorial conclusion
Adopt popwin if the windows that Emacs opens by itself are a recurring irritation, since the package turns them into dismissible popups without changing how any command works. Skip it if you use a modern completion UI or a window management package that already handles those buffers. Verify first which buffers you want in popups, because the default list is short and the configuration is opt-in by pattern, and that your Emacs version is supported, since the package claims testing from GNU Emacs 22 onwards.
Frequently asked questions
What problem does popwin solve in Emacs?
It deals with the buffers Emacs opens on your own behalf, such as *Help*, *Completions*, *compilation* and *Occur*, which normally appear in a window that splits your layout and then stays there after the command has finished. popwin shows those buffers in a popup window instead, and you can dismiss the popup by typing C-g at any time or by selecting another window.
How do I install and enable popwin?
The recommended route is MELPA, where the package is published on both MELPA and MELPA Stable. Manually you install popwin.el into your load-path directory, optionally using install-elisp or auto-install from a URL, then add `(require 'popwin)` and `(popwin-mode 1)` to your .emacs. The package is tested under GNU Emacs 22 or later, and it is a minor mode, so it can be toggled or bound to a key.
How do I configure which buffers popwin shows in a popup?
popwin:special-display-config is a list of entries, each of which is a (PATTERN . KEYWORDS) form. The pattern is a buffer name, a symbol specifying a major-mode, or a predicate function that takes the buffer, and if you push a string or a symbol then the pattern is that value and the keywords are empty. The keywords include :regexp to match names as a regular expression, :width and :height for the size, :position from left, top, right or bottom, :noselect to avoid moving focus, :dedicated, :stick and :tail.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/emacsorphanage-popwin)Was this useful?