FullstackPhoenix

Command Palette for Phoenix LiveView Apps

phoenixliveviewcommand-paletteui

Six months into a real SaaS, the navigation has grown three sidebars deep and your power users are tired of clicking. Linear, Slack, GitHub, and Notion have trained everyone to expect Cmd+K. The first time a customer says "wait, you don't have a command palette?", you know it's no longer optional.

This feature installs a keyboard-first launcher built with LiveView. It is not a generic search bar — it is a typed, protocol-driven result list that you teach about your domain by implementing one small protocol per resource type.

Make every page and record one hotkey away

A command palette is more than a UX nicety in a multi-tenant SaaS. It is the difference between an operator who can support a customer in twenty seconds and one who has to remember which submenu hides the team settings. The implementation pattern here keeps the search logic in your CommandPalette context and the formatting in a protocol you implement per type — so the palette grows with the product instead of becoming another tangle of cond statements.

What This Feature Adds

  • A CommandPaletteLive LiveView with a search input, result list, and keyboard navigation
  • A MyAppWeb.CommandPalette.Format protocol with header/1, label/1, and link/2 so each searchable type formats its own results
  • A Result struct so results are typed consistently regardless of source
  • A CommandPalette context that searches across configurable contexts (app, and admin when the admin feature is installed)
  • A hotkeys.js import added to assets/js/app.js so Cmd+K / Ctrl+K opens the palette anywhere in the app

How It Fits Into Your Phoenix Application

The palette is a LiveView you live_render into your layout. The protocol-based formatting is the part worth paying attention to: you teach the palette about a new resource by implementing MyAppWeb.CommandPalette.Format for the struct, not by editing the LiveView itself.

defimpl MyAppWeb.CommandPalette.Format, for: MyApp.Accounts.User do
def header(_), do: "Users"
def label(user), do: "#{user.name} (#{user.email})"
def link(user, :admin), do: ~p"/admin/users/#{user.id}"
def link(user, :app), do: ~p"/users/#{user.id}"
end

The context argument lets the palette show different links to admins than to regular users for the same record.

Installation Notes

  • No required dependencies. The palette works standalone, but it composes naturally with admin (which adds an admin context) and layouts (which gives it a sensible mount point).
  • Drop the palette into your layout once. After that, adding new searchable types is a defimpl, not another render call.
  • Hotkey conflicts are rare with Cmd+K, but Ctrl+K overlaps with the browser address bar shortcut on some platforms — test the binding in your target browsers.

Build This With Live SaaS Kit

Install saas_kit, then mix saaskit.feature.install command_palette to wire up Cmd+K navigation across your app and start teaching it your domain one protocol at a time.