# [_leptos-hotkeys_](https://github.com/gaucho-labs/leptos-hotkeys) [![All Contributors](https://img.shields.io/badge/all_contributors-6-orange.svg?style=flat-square)](#contributors-) Declaratively create and pair keybindings with callbacks for Leptos applications. [![Crates.io](https://img.shields.io/crates/v/leptos_hotkeys)](https://crates.io/crates/leptos_hotkeys) [![discord](https://img.shields.io/badge/Join-Discord-%235865F2.svg)](https://discord.gg/XhVbKk38ux) A person playing a burning piano at a sandy beach under a cloudy sky Leptos-hotkeys creates and manages keyboard shortcuts. It provides macros and functions that simplify the definition of keybindings, since the management of event lifecycle associated with keyboard interactions has been done for you! ## Live example Curious to see how it works? [See the demo](https://leptos-hotkeys.vercel.app). To get started, follow the [Quick Start](#quick-start) section. ## Features > [!NOTE] > This crate has three types of hotkeys: global, scoped, and focus-trapped. ### The `use_hotkeys!` Macro Use this macro to declare global and scoped hotkeys. This macro has js idioms while preserving Leptos standards. [More about the macro.](](#macro-api).) ### Global Hotkeys This example creates two global hotkeys: `W` and `F`. ```rust use leptos_hotkeys::use_hotkeys; #[component] pub fn SomeComponent() -> impl IntoView { let (count, set_count) = create_signal(0); // creating a global scope for the W key use_hotkeys!(("keyw") => move |_| { logging::log!("w has been pressed"); set_count.update(|c| *c += 1); }); // this is also a global scope for the F key! use_hotkeys!(("keyf", "*") => move |_| { logging::log!("f has been pressed"); set_count.update(|c| *c -= 1); }); view! {

Num Respects: {count}

} } ``` > [!TIP] > How do I write certain keys? See [Key Grammar](#keybinding-grammar). > [!NOTE] > The `*` symbol is reserved for the global scope_. > > The `W` hotkey omitted the scope parameter, implicitly making it global. ### Scoped Hotkeys Scopes provide context behind hotkeys. This context can be chained to a component, a state, or logic. This example shows an inner and outer scope and hotkeys that toggle scopes. ```rust use leptos_hotkeys::{use_hotkeys, use_hotkeys_context, HotkeysContext}; #[component] pub fn SomeComponent() -> impl IntoView { let HotkeysContext { enable_scope, disable_scope, .. } = use_hotkeys_context(); // switch into the inner scope use_hotkeys!(("keyi", "outer") => move |_| { disable_scope("outer"); enable_scope("inner"); }); // switch into the outer scope use_hotkeys!(("keyo", "inner") => move |_| { disable_scope("inner"); enable_scope("outer"); }); view! {
// outer logic residing...
// inner logic
} } ``` > [!NOTE] > Scopes are case-insensitive. That means `my_scope` and `mY_sCoPe` are considered the same scope. ### Focus trapped Hotkeys (the `use_hotkeys_ref!` macro) This example embeds a hotkey to a `

` tag. This hotkey will fire iff the element is focused and the scope is correct. ```rust use leptos_hotkeys::use_hotkeys_ref; #[component] pub fn SomeComponent() -> impl IntoView { let p_ref = use_hotkeys_ref!(("keyk", "*") => move |_| { // some logic }); view! {

p tag with node ref

} } ``` ## Quick Start ### Installation ```shell cargo add leptos_hotkeys ``` We also offer other feature flags that enhance developer experience, see [features](#features). ### `provide_hotkeys_context()` Call `provide_hotkeys_context()` in the `App()` component. This will provide the `HotkeysContext` for the current reactive node and all of its descendents. This function takes three parameters, the `node_ref`, a flag to disable blur events and a list of `initially_active_scopes`. `provide_hotkeys_context()` returns a `HotkeyContext`. To manage hotkeys, you can pull necessary signals out of `HotkeysContext`. ```rust use leptos_hotkeys::{provide_hotkeys_context, HotkeysContext, scopes}; #[component] pub fn App() -> impl IntoView { provide_meta_context(); let main_ref = create_node_ref::(); let HotkeysContext { .. } = provide_hotkeys_context(main_ref, false, scopes!()); view! {
// <-- attach main ref here!
} } ``` > [!NOTE] > If you're using [scopes](#scoped-hotkeys), you can initialize with a specific scope. ## That's it! [You can create global, scoped, and focus-trapped hotkeys!](#features) ### Keybinding Grammar `leptos_hotkeys` matches code values from [KeyboardEvent's](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code) `code` property. For reference, here's a list of [all code values for keyboard events](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values). You can bind multiple hotkeys to a callback. For example: ```txt "KeyG+KeyR,MetaLeft+KeyO,ControlLeft+keyK" ``` Keys are case-agnostic and whitspace-agnostic. For a hotkey with multiple keys, use the `,` as a delimiter in a sequence of keys. ### `scopes!()` Maybe you want to initialize a certain scope upon load, that's where the prop `initially_active_scopes` comes into play. Instead of having to create a `vec!["scope_name".to_string()]`, use the `scopes!()` macro. ```rust use leptos_hotkeys::{provide_hotkeys_context, scopes}; #[component] pub fn App() -> impl IntoView { let main_ref = create_node_ref::(); provide_hotkeys_context(main_ref, false, scopes!("scope_a", "settings_scope")); view! {
// ... routes
} } ``` ## The `debug` feature flag Improve developer experience by introducing the `debug` flag which adds logging to your console in CSR. It logs the current pressed key `code` values, hotkeys fires, and scopes toggling. Just simply: ```toml leptos_hotkeys = { path = "0.2.1", features = ["debug"] } ``` ## Contributors
Álvaro Mondéjar
Álvaro Mondéjar

💻
Robert Junkins
Robert Junkins

💻
LeoniePhiline
LeoniePhiline

📖
Gábor Szabó
Gábor Szabó

📖
Phillip Baird
Phillip Baird

🐛
zakstucke
zakstucke

🐛 💻