Skip to content

MudHotkey: Add new component for handling hotkeys#12079

Merged
danielchalmers merged 36 commits intoMudBlazor:devfrom
91378246:feature/global-hotkey-service
Dec 5, 2025
Merged

MudHotkey: Add new component for handling hotkeys#12079
danielchalmers merged 36 commits intoMudBlazor:devfrom
91378246:feature/global-hotkey-service

Conversation

@91378246
Copy link
Contributor

@91378246 91378246 commented Nov 7, 2025

This PR adds a new service: GlobalHotkeyService.
This service allows to registers global i.e. on all pages available hotkeys. This is useful to for example implement a global search popup, save your current work in a wiki application, show some info overlay, quickly navigate to a common target, etc.

image

@91378246
Copy link
Contributor Author

91378246 commented Nov 7, 2025

In regard to the failed "Check JS is ES6 compliant" step: Private fields and methods are compatible with all modern browsers: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_elements#browser_compatibility
=> Can i keep them?

@mudbot mudbot bot added awaiting triage Needs maintainer review or assistance enhancement Adds a new feature or enhances existing functionality (not fixing a defect) in the main library labels Nov 7, 2025
@Anu6is Anu6is requested a review from ScarletKuro November 7, 2025 15:38
@ScarletKuro
Copy link
Member

In regard to the failed "Check JS is ES6 compliant" step: Private fields and methods are compatible with all modern browsers: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_elements#browser_compatibility
=> Can i keep them?

No, since the build fails, it will affect other PRs, and we won't be able to make a release, etc.
I'm also not sure I like the AssemblyName part due to the trimming. We will need to explain to the user that they have to add [DynamicDependency(nameof(TheirMethodNameOfJSInvokable))] for their JSInvokable.

Why can't the GlobalHotkeyService contain the JSInvokable, and then have a method where the callback can be added, which is called by the JSInvokable? Something similar to what the KeyInterceptorService does.

@mudbot mudbot bot added needs: changes A maintainer has asked for further modifications to be made to this pull request and removed awaiting triage Needs maintainer review or assistance labels Nov 7, 2025
@91378246
Copy link
Contributor Author

91378246 commented Nov 7, 2025

Why can't the GlobalHotkeyService contain the JSInvokable, and then have a method where the callback can be added, which is called by the JSInvokable? Something similar to what the KeyInterceptorService does.

@ScarletKuro Because the dot net obj ref would break when i navigate away or reload or am I mistaken? That was the intention why I used the static method approach at all because I couldn't find another way how I could make it work on a application wide level.

@ScarletKuro
Copy link
Member

@ScarletKuro Because the dot net obj ref would break when i navigate away or reload or am I mistaken?

Can you explain it in more detail, with examples? If you force a reload or navigate away, you obviously need to re-register the callback but I don’t see a problem with that. If you perform an SPA navigation to another page, you’d need to add a handler for that specific page. I don’t see an issue with that either.

That was the intention why I used the static method approach at all because I couldn't find another way how I could make it work on a application wide level.

I find it troublesome if it has to be static, because that introduces a lot of restrictions since you can’t access local members, methods, etc., which makes the design poor for the user as you have to access things statically. For example, Toolbelt.Blazor.HotKeys2 uses JSInvokable in the way I described. For me, this library is a role model, which is why I’ve rejected all feature requests proposing to add global hotkey support, since a third-party solution already exists (and we don’t aim to make this an all-in-one library). However, if the implementation is very minimal and clean, we could consider it.

@91378246
Copy link
Contributor Author

91378246 commented Nov 9, 2025

@ScarletKuro I changed it to the following (please note that the code is just a proof of concept atm, the provider is prob. not needed):

<MudHotkeyProvider>
   <MudHotkey T="HotkeyServiceExample_Snackbar" Key="JsKey.KeyB" KeyModifiers="[JsKeyModifier.Control]" />
</MudHotkeyProvider>

This would allow the user to easily add for example a custom popup which opens on a certain hotkey easily, either by adding it into the MainLayout for a global hotkey or into a page for a lokal hotkey. The service will then get removed and the functions would be moved into the MudHotkeyProvider.

Is that more in line with what you had in mind?

@ScarletKuro
Copy link
Member

ScarletKuro commented Nov 9, 2025

Is that more in line with what you had in mind?

I guess so. That idea with provider looks interesting, and it makes sense if you want to have global hotkeys across the whole app.

Few things to consider:

  1. Passing parameters. What if I want to pass parameters to HotkeyServiceExample_Snackbar? Maybe DynamicComponent could be used for that.
  2. Non-UI actions. What if I don’t want to open a RenderFragment \ component on a hotkey, but instead perform some action (like an API call) or focus the search bar in the app bar? This probably needs to be more flexible than just a “custom popup.” I’ve never personally needed global hotkeys, so this is just a suggestion. It would be great if @danielchalmers, @versile2, and @Anu6is could join the conversation.
  3. Global vs. per-page. Should this only be a global feature? It might be nice if individual pages could subscribe to hotkeys too, not just globally. For example, on page A pressing F1 could show one guide popup, while on page B it could show another. Of course, this could be handled on global level, so maybe that’s not the best example, but from a design perspective, managing it per page might be easier. Perhaps some kind of subscription service (or multiple provider support?) should exist for individual subscriptions. I see it something that you could do globally on a provider like your example and then per-page. Again, just an idea.
  4. Should this be transient? While it doesn’t have a disposable, so it won't hit this Docs: Add Services page #11967 (comment), I still feel like making it scoped or maybe even a singleton might make more sense, depending on the architecture of point 3 (which is still debatable whether we need this?).

@91378246
Copy link
Contributor Author

91378246 commented Nov 9, 2025

@ScarletKuro Then what about this: A simple component instead of the service (code is again not finalized):

  • You can either add it to your MainLayout or to your page = global or local shortcut
  • You can pass any component as child
  • You have an event callback for code only
  • Intuitive and easy to use
  • (I would then implement it in a way where a local hotkey could overwrite a global hotkey, allowing for more flexibility)
<MudHotkey Key="JsKey.KeyB" KeyModifiers="[JsKeyModifier.Control]" HideChildContentOnRepress="true">
   <SomeDialog />
</MudHotkey>
<MudHotkey Key="_selectedKey" KeyModifiers="_selectedKeyModifiers" OnHotkeyPressed="OnHotkey" />

@ScarletKuro
Copy link
Member

Sounds good to me

@mudbot mudbot bot changed the title Feature: Global hotkey service MudHotkey: Add new component for handling hotkeys Nov 9, 2025
@mudbot mudbot bot removed the needs: changes A maintainer has asked for further modifications to be made to this pull request label Nov 9, 2025
@danielchalmers
Copy link
Member

If we're making breaking changes soon, can we merge this with the KeyInterceptorService and refactor the usage across the library?

I'm also not sure about making it a component as it seems like more complexity. What if you need to handle multiple hotkeys for one child?

@mudbot mudbot bot added needs: changes A maintainer has asked for further modifications to be made to this pull request new component Proposal or addition of a new component (apply this instead of enhancement) labels Nov 9, 2025
This was referenced Feb 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new component Proposal or addition of a new component (apply this instead of enhancement)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants