Keyboard Shortcuts
Avo ships with a built-in keyboard shortcut system that lets users navigate and operate the admin panel without touching the mouse. Press ? at any time to open the shortcuts reference modal, which lists every shortcut available on the current page.
With no configuration, all shortcuts are enabled and each bound button or link renders a small badge — for example C on a Create button — hinting at its shortcut. A shortcut without Cmd/Ctrl or Alt never fires while you're typing in an input, textarea, select, or contenteditable field, so search boxes and form fields behave normally; a chord with one of those reaches fields.
Configure keyboard shortcuts
Keyboard shortcuts are controlled through config.hotkeys:
# config/initializers/avo.rb
Avo.configure do |config|
config.hotkeys = {
enabled: true, # master switch for all keyboard shortcuts
show_key_badges: true # show the inline <kbd> badges next to buttons and links
}
endSet enabled: false to turn the whole system off — no shortcuts fire and the key badges disappear. Set show_key_badges: false to keep the shortcuts working but hide the inline badges from the UI.
Both default to true, so you only need to set the keys you want to change.
Change or disable a shortcut
Sinceavo >= v4.3.6Every shortcut in the tables below has a stable ID. Rebind it, or turn it off with false, through bindings:
# config/initializers/avo.rb
Avo.configure do |config|
config.hotkeys = {
bindings: {
"record.edit": "Shift+E", # edit with Shift+E instead of E
"record.delete": false, # no delete shortcut at all
"index.next_row": "j,ArrowDown", # either key moves to the next row
"advanced_search.open": "Mod+/" # add-on shortcuts work the same way
}
}
endShortcuts you don't list keep their defaults. The new key shows up everywhere the old one did: it fires the action, appears on the button's badge, and is listed in the ? modal. A disabled shortcut disappears from all three.
Keys are written in the @github/hotkey format: Mod+k is Cmd+K on macOS and Ctrl+K elsewhere, a space makes a sequence (g i), and a comma lists alternatives (j,ArrowDown); badges and the ? modal show the first one. The full list of IDs is on the reference page. A key without Cmd/Ctrl or Alt never fires while you type in a field, so binding the search palette to a plain letter is safe; a chord with one reaches fields, which is how the assistant's Mod+j works.
Avo checks your bindings when the app boots and raises if an ID is misspelled, if two shortcuts that can fire on the same page share a key, or if a single key would block a sequence (binding v alone would stop V T from ever firing).
Fixed keys
Esc and Cmd/Ctrl+↵ close and submit every modal and form, so they can't be rebound. The arrow keys, ↵ and Space inside tables, menus and editors are fixed too.
Global shortcuts
These shortcuts are available from anywhere in the admin panel.
| Keys | Action |
|---|---|
| ? | Open/close the keyboard shortcuts modal |
| Cmd+K / Ctrl+K | Focus the global search |
| Shift+\ | Toggle the sidebar |
| Shift+T | Focus the page content (then Tab into it) |
| Shift+K | Toggle the shortcut key badges |
| B | Go back |
| r r r | Reload the page (preserves scroll position) |
| ↑ / ↓ | Navigate options inside a modal |
| Esc | Close modal / unfocus field |
Shift+K hides or shows the inline badges for the current browser (the choice is remembered). It only works when show_key_badges isn't set to false.
Appearance shortcuts
Cycle the appearance settings from any page.
| Keys | Action |
|---|---|
| Shift+M | Cycle the color scheme (auto / light / dark) |
| Shift+N | Cycle the neutral theme |
| Shift+A | Cycle the accent color |
| Shift+S | Toggle the pick sound |
Assistant
Requires the Avo AI add-on. Without it, the shortcut isn't bound and doesn't show up in the ? modal.
| Keys | Action |
|---|---|
| Cmd+J / Ctrl+J | Open the assistant |
Its chord has a modifier, so it fires while you're typing in a field — pulling the assistant up mid-edit is the point. Rebind it to a key without Cmd/Ctrl or Alt and it stays out of fields like every other shortcut. It follows enabled like the rest, so config.hotkeys = {enabled: false} turns it off along with everything else.
Index view
| Keys | Action |
|---|---|
| / | Focus the resource search input |
| C | Create a new record |
| A | Open the actions menu |
| J / K | Focus the table and move to the next / previous row |
| ↑ / ↓ | Navigate rows (once the table is focused) |
| ↵ | Open the focused record |
| Space | Select / deselect the row |
| E | Edit the focused record |
| D | Delete the focused record |
| A | Open the focused row's actions list, when its row controls have one |
| Esc | Clear row focus / deselect rows |
| V T | Switch to table view |
| V G | Switch to grid view |
| V M | Switch to map view |
Use J / K to jump into the table from anywhere on the page; the arrow keys take over once a row is focused.
Show view
| Keys | Action |
|---|---|
| E | Edit the record |
| D | Delete the record |
| A | Open the actions menu |
| C | Create a new record |
| I | Go back to the index |
C follows the same authorization as the index's create button: if the user can't create the record, the key does nothing.
Edit view
| Keys | Action |
|---|---|
| Cmd+↵ / Ctrl+↵ | Submit the form |
| I | Go back to the index |
| Esc | Unfocus the current field |
Modals
| Keys | Action |
|---|---|
| Cmd+↵ / Ctrl+↵ | Submit the modal's form (run the action, attach, save) |
| Esc | Cancel / close the modal |
Cmd+↵ works from inside a field too, and in any modal that wraps or contains a form: action modals, the attach modal, the "Create new" modal of a belongs_to field, and modals your own views render with Avo::ModalComponent, including ones a Turbo Stream inserts. It submits with the modal's primary submit button, so that button's name/value are sent. If that button is disabled, nothing happens.
Assign hotkeys to the sidebar menu
The avo-menu DSL supports a hotkey: option on any item type, letting users jump straight to a sidebar section from anywhere in the admin panel.
# config/initializers/avo.rb
Avo.configure do |config|
config.main_menu = -> {
section "Content", icon: "tabler/outline/files" do
resource :post, hotkey: "g p"
resource :category, hotkey: "g c"
link "Analytics", path: "/avo/analytics", hotkey: "g a"
end
}
endThe menu item automatically renders a key badge next to its label and registers the binding. Hotkey strings use the @github/hotkey format — space-separate keys for a sequence like g p.
For resource items you can set the hotkey on the resource class instead, and it applies wherever that resource appears in the menu:
class Avo::Resources::Post < Avo::BaseResource
self.hotkey = "g p"
endAdd your own shortcuts
Avo binds shortcuts declaratively through data-hotkey attributes, so any button or link you render in a custom tool or partial can opt in:
<a href="/avo/posts/new" data-hotkey="c">New post</a>Use Mod for a key that should be Cmd on macOS and Ctrl elsewhere, and a comma for alternatives. A space means a sequence, not an alternative:
<button data-hotkey="Mod+s">Save</button>
<a href="/avo/reports" data-hotkey="g r,Shift+R">Reports</a>Bindings are re-applied on every Turbo navigation, so they survive turbo:load and turbo:frame-render without extra work.
Shortcuts hidden inside association panels
When a resource is rendered inside an association panel — as a has_many, has_one, or similar relation on another record's show page — some shortcuts are intentionally suppressed to avoid ambiguity:
- Create (C) and Actions (A) — hidden because the show page may host several association panels, so a single C or A can't know which one to target.
- Edit (E) and Delete (D) — hidden because they belong to the show view of the top-level record, not to an association row.