Destiner's Notes

Designing a Command Palette

21 April 2022

Command Palette, a UI pattern that seems to be everywhere, yet it is in nowhere near all places where it should be, is a surprisingly good invention. There’s hardly anyone who hates it, while many absolutely love it.

While making an input and a list of results might seem like an easy thing to nail, I’d argue most implementations out there are flawed, each in its own way.

Introduction

First, let’s define what makes a decent command palette. At its simplest, you need a hotkey to show the modal, an input to enter the query, and a list of results.

Pioneered by Sublime Text, the command palette first served as a way to fuzzy search through obscure features of the text editor hidden in menu. In a decade, the palette in Sublime Text surprisingly didn’t change much, but as other products inherited the same pattern, many innovations and refinements were made. If you want to know how the reasoning behind a command palette evolved across products, check out this article.

As a regular user of Sublime Text, I can’t even comprehend how useful the palette is for me. It’s so tied to my workflow I don’t even notice using it. But its importance is hard to overstate: I don’t really use the app’s menu, yet I interact with many of its items via palette.

Command palette was predominantly used in desktop software. Recently, though, more and more web-first services adopt the pattern (GitHub, Netlify, Linear). There’s even a company that provides Command Palette as a Service.

Features

Let’s look at what makes a decent command palette a perfect one. I’d argue that most if not all of those features are a necessity for a good UX.

I will illustrate my points by highlighting implementations in various apps and services. I will blame Sublime Text a lot since I’ve used it daily for years and know it much better than any other software mentioned here. Many of Sublime’s flaws were inherited by other text editors, like VS Code.

Listing all actions

At the very least, a command palette should include anything available via the application’s menu. Also, it should include all context menu actions as well. Sublime Text is probably the worst here: not only it doesn’t include all the menu actions, but it also misses most of the context menu items. Why its command palette has the “Rename File” action, but not “Delete File” or “Reveal in Finder” is beyond me. Adding those and a few more actions (like “Move File” or “Create File Here”) and I could manage project files without touching the mouse or opening Finder ever again!

On the flip side, I don’t think that a command palette should include each and every configuration preference of the app. Having a command to open the preference pane is a must, but anything above that would be too noisy.

Raycast is definitely on the “too much” side here. By default, the command palette lets you run not only applications you installed and use every day, but also low-level OS utils like “Disk Utility” and “Keychain Access”, and even each System Preferences option. Is it really necessary? At least providing a way to toggle those off quickly would be a huge win.

User-installed applications, built-in system apps, utilities, and system preferences all enabled by default and have to be toggled one-by-one in Raycast

Showing hotkeys

Given that many commands available from the palette have hotkeys, it would be a waste of electronic real estate not to show them.

You can go even further and provide a way to assign and change hotkeys right from the palette. This is exactly what CommandBar did.

GitHub missed the opportunity to highlight their rich set of shortcuts in the palette.

Raycast is a system-wide application, so it can’t provide the ability to assign hotkeys to commands. Instead, it has aliases that allow you to assign catchy shortcuts to any command.

Raycast aliases in action

Conventional hotkey

The palette should be always quickly available, and since it’s a keyboard-based tool, you need a simple, memorable shortcut to run it.

Sublime Text uses ⌘ + P for a search tool, and ⌘ + Shift + P for the palette. I wish it was the other way (or better, a single hotkey to run them both), but that seems to stick, and now VS Code uses the same.

Using ⌘ + P might conflict with the “Print” action. Both Apple and Microsoft suggest not to use conventional hotkeys for custom actions in their guidelines.

Acorn uses ⌘ + Shift + O to toggle the palette, which I find inconvenient. On the flip side, iA Writer uses the same hotkey, so maybe it’s not that uncommon.

On the web, ⌘ + K is the de-facto standard, and you need a convincing reason not to use it. Another common option is ⌘ + /.

For an input-based tool, a command palette shouldn’t be too strict about what input corresponds to which command. First of all, users tend to forget the exact name of commands they use. Second, typos happen, and the additional cognitive load required to find and fix the mistake kills the flow. Third, it’s just faster to type ssmd in Sublime instead of Set Syntax: Markdown. Using fuzzy search solves all these inconveniences.

Raycast is lagging here by requiring an exact substring match. It has, however, another great feature that I miss elsewhere, where an extension developer can assign keywords to each item so that the items can be also found by entering one of the keywords.

Favorites

When you use the palette a lot, you may realize that you often use a small subset of all commands. I don’t have exact data, but I’d assume I use 4 or 5 commands in Sublime Text about 50% of the time. Having quick access to favorite actions will improve the workflow.

This could also be solved more subtly by forming a dynamic list of most used commands.

Raycast allows to favorite frequently used commands and use '⌘ + 1-9' hotkeys to run them.

Discoverability

As a palette might have hundreds of commands, discovering new ones is a problem. A great opportunity to aid discovery is to provide suggestions as the palette starts. What should be suggested to the user is up to the developer. Recent queries, frequently used commands, recommendations based on the usage data, AI, ML, blockchain — the sky is the limit.

Acorn does a bad job here: on palette launch, it shows nothing but an input. Sublime Text is not much better: it shows the list of all commands sorted alphabetically, which is equally useless.

A good palette guides the user through its capabilities and provides usage examples.

GitHub palette on launch

Single entry point

Here, I will bash again at Sublime Text. It has a few palette-like navigation utilities, like “Go To File”, “Go To Line”, and “Go To Symbol”, which are all great… except I almost don’t use any of them. Thing is, remembering which set of hotkeys corresponds to which “Go To X” command just doesn’t work for me.

Funny enough, Sublime partially solved this mess by having a query prefix: instead of using a separate hotkey for each command, you can prepend the query with ”@” or ”:” to switch to “Go To Symbol” and “Go To Line” accordingly.

Sublime Text has so many different 'palettes' that they take up a whole menu item section

Extendable by plugins

This is somewhat obvious, but it is still worth highlighting it out of its importance. If an application or service can be extended by third-party plugins, these plugins should be able to add new commands to the palette. Optionally, an app may provide a way for users to turn some of the commands off.

Commands provided by Raycast extensions can be turned off individually

Togglable

Nitpicking: a command palette should be togglable, i.e. it should disappear when using its launch hotkey again.

Optional: multi-level palette

For a more complex workflow, a command palette may store context and provide multiscreen navigation. I would be cautious not to turn the palette into a separate app with an equal complexity, though.

For example, GitHub’s palette allows you to quickly look up organizations, accounts, and repositories, as well as to navigate between code, issues, and pull requests.

Raycast extensions are more like apps inside a command palette that leverage forms, lists, and markdown output.

An example of Raycast extension

If your application works with user-created data, it makes a lot of sense to utilize the palette as a search engine for said data.

The implementation may vary. One option would be to “inline” search results so that they show up along with commands. Another way to implement search is to add some special syntax, for example, treating a query with a ”?” prefix as a search query. Finally, you can leverage a multi-level palette: a user would find a “search” command first and then will enter the query.

Showcase

Finally, I’d like to go through a few well-done palettes. While all implementations are flawed in some way, some of them don’t feel broken.

Raycast

Raycast, a command palette for OS, took the idea behind Alfred to the next level. By default, Raycast provides a Spotlight-like search over your applications and offers some handy utilities like currency convertor, window manager, and volume control. But Raycast also has a flexible extension framework, which makes it possible to build complex UIs, process files, prompt user input, or send network requests. Raycast extensions are perfect for developer utilities, quick shortcuts for other apps, and thin clients for web services.

Raycast music extension

GitHub

GitHub’s palette is a great tool to navigate between the projects you’re working on. It has a steep learning curve, but it is helpful from the start. Its built-in search shows results right in the palette.

GitHub palette can be used as a navigation tool