Skip to content
How-to guides and worked examplesSee the guides →

Keyboard Shortcuts API ​

The per-option reference for config.hotkeys. For how-to guides, see Keyboard Shortcuts. All options go in config/initializers/avo.rb:

ruby
# config/initializers/avo.rb
Avo.configure do |config|
  config.hotkeys = {
    enabled: true,
    show_key_badges: true,
    bindings: {
      "record.edit": "Shift+E"
    }
  }
end

Each key is merged with its default, so a hash that sets only bindings keeps enabled and show_key_badges at true.

Switches ​

enabled

Master switch for every keyboard shortcut, including add-on shortcuts and the ? modal.

ruby
config.hotkeys = {
  enabled: false
}
  • Type: Boolean
  • Default: true

show_key_badges

Renders the inline key badges on buttons, links and search inputs. Shortcuts keep working when it's false, and users can no longer toggle badges with Shift+K.

ruby
config.hotkeys = {
  show_key_badges: false
}
  • Type: Boolean
  • Default: true

Bindings ​

bindings

Since avo >= v4.3.6

Rebinds or disables shortcuts by ID. Each value is a key in the hotkey syntax, or false to disable the shortcut. IDs you leave out keep their default.

ruby
config.hotkeys = {
  bindings: {
    "record.edit": "Shift+E",
    "record.delete": false,
    "index.next_row": "j,ArrowDown"
  }
}
  • Type: Hash of String or Symbol ID to String or false
  • Default: {}
  • Values: any ID from Shortcut IDs
  • Validation: raises ArgumentError at boot when:
    • an ID is unknown in a namespace that exists ("record.edti");
    • a value is neither a String nor false;
    • two shortcuts that can fire on the same page share a key;
    • a single key is the start of another shortcut's sequence (v would block v t);
    • a value uses a fixed key.
  • Add-ons: IDs for an add-on that isn't installed are ignored, so one initializer works across apps with different add-ons.

Two shortcuts may share a key when they never render on the same page. For example, resource.go_to_index (show and edit) can use /, which index.focus_search uses only on the index.

Hotkey syntax ​

Keys use the @github/hotkey string format, the same format as data-hotkey attributes and the menu's hotkey: option. The library's Hotkey Mapper shows the string for any key you press.

RuleExampleMeaning
Keys use W3C key names, matched against event.keyEnter, ArrowDown, /
+ joins modifiers to a key, in the order Control+Alt+Meta+Shift+KEYControl+Alt+hCtrl, Alt and H together
Mod is Cmd on macOS and iOS, Ctrl elsewhere. Don't combine it with Control or MetaMod+kCmd+K / Ctrl+K
A space makes a sequenceg iG, then I within 1.5 seconds
A comma separates alternativesj,ArrowDownJ or ↓
Uppercase letters and shifted symbols include ShiftShift+A, Shift+?not A or ?
Plus and Space name the + and space keysShift+Plus
A comma right after a key is the comma keyControl+,,xCtrl+, or X

Keyboard layouts

Shift+? and Shift+| also match on layouts where those symbols sit elsewhere, and letter shortcuts also match by physical key on non-Latin layouts (Cyrillic, Greek).

Key badges and the ? modal show the first alternative of a binding.

Shortcut IDs ​

Core ​

IDDefaultActionWhere it fires
shortcuts.toggleShift+?Open/close the keyboard shortcuts modaleverywhere
navigation.focus_contentShift+TFocus the page contenteverywhere
navigation.go_backbGo backeverywhere
navigation.reloadr r rReload the page, keeping the scroll positioneverywhere
sidebar.toggleShift+|Toggle the sidebareverywhere
hotkeys.toggle_badgesShift+KToggle the key badgeseverywhere
appearance.cycle_schemeShift+MCycle the color schemeeverywhere
appearance.cycle_neutralShift+NCycle the neutral themeeverywhere
appearance.cycle_accentShift+ACycle the accent coloreverywhere
appearance.toggle_soundShift+SToggle the pick soundeverywhere
resource.newcCreate a new recordindex, show
resource.actionsaOpen the actions menuindex, show, edit, focused index row
resource.go_to_indexiGo back to the indexshow, edit
record.editeEdit the recordshow, focused index row
record.deletedDelete the recordshow, focused index row
index.focus_search/Focus the resource searchindex
index.next_rowjFocus the table and move to the next rowindex
index.previous_rowkFocus the table and move to the previous rowindex
index.view_tablev tSwitch to table viewindex
index.view_gridv gSwitch to grid viewindex
index.view_mapv mSwitch to map viewindex

resource.new also drives the create buttons on the Avo AI chats page and the kanban board.

Add-ons ​

An add-on's IDs start with its gem name minus avo-: avo-advanced_search registers advanced_search.*.

IDDefaultActionAdd-on
advanced_search.openMod+kFocus the global searchAdvanced search
advanced_search.focus_resultsMod+Shift+KFocus the search input on the dedicated results pageAdvanced search
ai.toggle_assistantMod+jOpen the assistant. Fires from inside fields tooAvo AI

Fixed keys ​

These keys can't be rebound or used in bindings:

KeysAction
EscapeClose the modal, cancel the action, unfocus the field
Mod+EnterSubmit the form or modal

Navigation keys inside a widget (the arrows, Enter and Space in tables, menus, the lightbox and editors) aren't shortcuts and aren't configurable either.

Plugin shortcuts ​

Plugins register their shortcuts on the object Avo.plugin_manager.register returns, inside the plugin's avo_boot hook. The ID's namespace comes from the gem name, so avo-dynamic_filters gets dynamic_filters.*.

ruby
ActiveSupport.on_load(:avo_boot) do
  Avo.plugin_manager.register("avo-dynamic_filters")
    .register_hotkey(:open, default: "f", label: "Open filters", section: "Index view", scopes: [:index])
end

Render the bound key with Avo::Hotkeys.key_for("dynamic_filters.open") in data-hotkey, or match it in a keydown listener with window.Avo.hotkeys.matches(event, "dynamic_filters.open").

register_hotkey

Adds a shortcut to the registry, the bindings validation and the ? modal.

  • Type: method on Avo::Plugin, returns the plugin so calls chain
  • Arguments:
    • action (Symbol) — the part of the ID after the namespace.
    • default: (String) — the default key, in the hotkey syntax.
    • label: (String) — the row text in the ? modal.
    • section: (String) — the modal section to list it under. A section core doesn't have is added at the end.
    • scopes: (Array of :global, :index, :show, :edit) — the pages it fires on, used to detect conflicts. Default [:global].
  • Validation: raises ArgumentError when the namespace equals a core namespace (record, index, navigation...).