Keyboard Shortcut Service

Global keyboard shortcut management for application-wide hotkeys. Register, suspend, and unregister shortcuts with automatic input element detection and cross-platform modifier support.

Basic Usage

Register a simple keyboard shortcut using RegisterAsync. The returned IDisposable handle lets you unregister the shortcut when no longer needed.
_shortcut = await KeyboardShortcutService.RegisterAsync("Ctrl+K", async () =>
{
    // Handle shortcut
    await Task.CompletedTask;
});

Multiple Shortcuts

Register shortcuts with different modifier combinations using Ctrl, Shift, Alt, and Meta. Try pressing them!
// Ctrl shortcuts
_saveShortcut = await KeyboardShortcutService.RegisterAsync("Ctrl+S", HandleSave);
_saveAsShortcut = await KeyboardShortcutService.RegisterAsync("Ctrl+Shift+S", HandleSaveAs);
_newShortcut = await KeyboardShortcutService.RegisterAsync("Ctrl+N", HandleNew);

// Alt shortcut
_altShortcut = await KeyboardShortcutService.RegisterAsync("Alt+Q", HandleQuickActions);

// Meta (Windows key) shortcut
_metaShortcut = await KeyboardShortcutService.RegisterAsync("Meta+M", HandleSystemMenu);

// Don't forget to dispose
public void Dispose()
{
    _saveShortcut?.Dispose();
    _saveAsShortcut?.Dispose();
    _newShortcut?.Dispose();
    _altShortcut?.Dispose();
    _metaShortcut?.Dispose();
}

Suspend During Dialog

Use Suspend and Resume to temporarily disable all shortcuts while a dialog or modal is open, preventing conflicts with dialog-specific interactions.
// Suspend shortcuts when opening a dialog
private void OpenDialog()
{
    _dialogOpen = true;
    KeyboardShortcutService.Suspend();
}

private void CloseDialog()
{
    _dialogOpen = false;
    KeyboardShortcutService.Resume();
}

// Handle dialog dismissed via click-outside or Escape
private void OnDialogOpenChanged(bool isOpen)
{
    _dialogOpen = isOpen;
    if (!isOpen)
    {
        KeyboardShortcutService.Resume();
    }
}

Conditional Shortcuts

Dynamically register and unregister shortcuts based on application state. Toggle editing mode to enable or disable the shortcut.
private bool _editMode;
private IDisposable? _conditionalShortcut;

private async Task OnEditModeChanged(bool enabled)
{
    _editMode = enabled;

    if (enabled)
    {
        // Register shortcut when entering edit mode
        _conditionalShortcut = await KeyboardShortcutService.RegisterAsync("Ctrl+D", async () =>
        {
            await DuplicateItem();
        });
    }
    else
    {
        // Unregister when leaving edit mode
        _conditionalShortcut?.Dispose();
        _conditionalShortcut = null;
    }
}

public void Dispose()
{
    _conditionalShortcut?.Dispose();
}

Installation

dotnet add package BlazorBlueprint.Primitives

Setup

The service is automatically registered when you add BlazorBlueprint services in Program.cs.

Program.cs
builder.Services.AddBlazorBlueprintPrimitives();

Usage

_Imports.razor
@using BlazorBlueprint.Primitives.Services
@inject IKeyboardShortcutService KeyboardShortcutService
@inject IKeyboardShortcutService KeyboardShortcutService
@implements IDisposable

<p>Press Ctrl+K to trigger the shortcut</p>

@code {
    private IDisposable? _shortcut;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            _shortcut = await KeyboardShortcutService.RegisterAsync("Ctrl+K", async () =>
            {
                Console.WriteLine("Shortcut triggered!");
                await Task.CompletedTask;
            });
        }
    }

    public void Dispose()
    {
        _shortcut?.Dispose();
    }
}

Shortcut String Format

Shortcuts are defined as strings with modifiers and a key separated by +.

Supported Modifiers

Ctrl/Control

Also: Cmd, Command

Shift

Shift key

Alt

Also: Option, Opt

Meta

Also: Win, Windows

Supported Special Keys

The following special keys are supported and can be used with or without modifiers. Aliases are accepted during parsing and normalized automatically.

Key Aliases Example
Escape Esc "Escape"
Enter Return "Ctrl+Enter"
Space Spacebar "Ctrl+Space"
Tab "Ctrl+Tab"
Backspace Back "Ctrl+Backspace"
Delete Del "Shift+Delete"
Insert Ins "Shift+Insert"
Home "Ctrl+Home"
End "Ctrl+End"
PageUp PgUp "PageUp"
PageDown PgDn "PageDown"
ArrowUp Up "Alt+ArrowUp"
ArrowDown Down "Alt+ArrowDown"
ArrowLeft Left "Ctrl+ArrowLeft"
ArrowRight Right "Ctrl+ArrowRight"
F1F12 "F1", "Ctrl+F5"

Examples

// Simple shortcuts
"Ctrl+S"       // Save
"Ctrl+Z"       // Undo
"Delete"       // Delete key only

// With Shift
"Ctrl+Shift+S" // Save As
"Ctrl+Shift+Z" // Redo

// With Alt
"Alt+F4"       // Close (careful - browser may intercept)
"Ctrl+Alt+T"   // Custom action

// Function keys
"F1"           // Help
"Ctrl+F5"      // Force refresh

// Special keys
"Escape"       // Escape key
"Enter"        // Enter key
"Space"        // Spacebar

// Arrow keys
"Alt+ArrowUp"  // Move up
"Alt+Down"     // "Down" is an alias for "ArrowDown"

// Navigation keys
"Ctrl+Home"    // Go to start
"Ctrl+End"     // Go to end
"PageUp"       // Page up
"PgDn"         // "PgDn" is an alias for "PageDown"

Behavior

Input Element Skipping

Shortcuts are automatically disabled when the user is typing in form elements. This prevents shortcuts from interfering with text input. The following elements are skipped:

  • <input> — all input types (text, number, email, etc.)
  • <textarea> — multiline text areas
  • <select> — dropdown selects
  • contenteditable — any element with contenteditable attribute

Cross-Platform Modifier Keys

Ctrl and Meta (Cmd on macOS) are treated as equivalent. A shortcut registered as "Ctrl+S" will fire when the user presses Ctrl+S on Windows/Linux or Cmd+S on macOS. You don't need to register both.

Default Action Prevention

When a registered shortcut is triggered, the browser's default action for that key combination is automatically prevented. For example, registering "Ctrl+S" will prevent the browser's "Save Page" dialog from appearing.

API Reference

IKeyboardShortcutService Methods

Registration

Property Type Default Description
RegisterAsync(string, Func<Task>) Task<IDisposable> - Register a shortcut with auto-generated ID. Returns a disposable handle to unregister.
RegisterAsync(string, Func<Task>, string) Task<IDisposable> - Register a shortcut with a specific ID for later unregistration via Unregister().
Unregister(string) void - Unregister a shortcut by its ID. Prefer disposing the handle returned by RegisterAsync instead.

Lifecycle

Property Type Default Description
Suspend() void - Suspend all shortcut handling globally (e.g., while a dialog is open).
Resume() void - Resume shortcut handling after suspension.

Properties

State

Property Type Default Description
IsSuspended bool false Whether shortcut handling is currently suspended.

Best Practices

Register in OnAfterRenderAsync

Always register shortcuts in OnAfterRenderAsync with the firstRender guard. The service relies on JavaScript interop, which is only available after the component has rendered.

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        _shortcut = await KeyboardShortcutService.RegisterAsync("Ctrl+K", HandleShortcut);
    }
}

Always Dispose Registrations

Implement IDisposable and dispose all shortcut handles when the component is destroyed. Failing to dispose will leave stale shortcuts registered that reference a destroyed component.

@implements IDisposable

@code {
    private IDisposable? _shortcut1;
    private IDisposable? _shortcut2;

    public void Dispose()
    {
        _shortcut1?.Dispose();
        _shortcut2?.Dispose();
    }
}

Suspend During Modals

Call Suspend() when opening dialogs, sheets, or drawers that have their own keyboard interactions. Remember to Resume() when they close — including when the user dismisses them by clicking outside or pressing Escape.

Avoid Reserved Browser Shortcuts

Some keyboard shortcuts are reserved by browsers and cannot be intercepted. While preventDefault works for most combinations, the following are typically blocked at the browser/OS level:

Browser Shortcut Conflicts

Some keyboard shortcuts are reserved by browsers and cannot be overridden. Avoid using:

  • Ctrl+T - New tab
  • Ctrl+W - Close tab
  • Ctrl+N - New window (in some browsers)
  • Ctrl+Tab - Switch tabs
  • F5 / Ctrl+R - Refresh
  • F11 - Fullscreen
  • F12 - Developer tools