#callback #leptos #optional #events #flexible #handler #maybe

leptos-maybe-callback

Zero-cost, type-safe optional callbacks for Leptos with flexible event handling

2 releases

0.0.3 Jan 5, 2025
0.0.1 Jan 5, 2025

#1203 in Web programming

Download history 207/week @ 2025-01-01 27/week @ 2025-01-08

234 downloads per month

MIT license

11KB
142 lines

Leptos Maybe Callback

Lightweight, type-safe optional callbacks for Leptos. Provides a zero-cost abstraction for conditionally handling event callbacks in your Leptos components.

Features

  • Optional Callbacks: Represent callbacks that may or may not exist.
  • Zero-Cost Abstraction: Minimal overhead using Rust's Option and enums.
  • Seamless Integration: Works effortlessly with Leptos signals and components.
  • Flexible Conversions: Convert from various callback-like types, including nested Options and Fn closures.
  • Thread-Safe & Wasm-Ready: Implements Send + Sync where applicable.
  • Convenient Handler Generation: Utilize as_handler and into_handler methods for generating event handlers.

Installation

Add to your Cargo.toml:

[dependencies]
leptos-maybe-callback = "0.4.0"

Usage Examples

Component with Optional Callback Prop

Define a component that accepts an optional callback using #[prop(into, optional)]. This allows passing a closure, a Callback, or omitting the prop.

use leptos::prelude::*;
use leptos_maybe_callback::MaybeCallback;

/// A button component with an optional `onclick` callback.
#[component]
#[allow(non_snake_case)]
pub fn Button(
    #[prop(into, optional)]
    onclick: MaybeCallback<MouseEvent>,
) -> impl IntoView {
    view! {
        <button on:click=onclick.into_handler()>
            "Click me"
        </button>
    }
}

Using the Component with a Closure

Use the Button component and provide a closure for the onclick prop.

use leptos::prelude::*;
use leptos_maybe_callback::MaybeCallback;

/// Parent component using `Button` with a closure.
#[component]
#[allow(non_snake_case)]
pub fn ButtonWithClosure() -> impl IntoView {
    view! {
        <div>
            <Button onclick=|_| log::info!("Clicked via closure!") />
            <Button />
        </div>
    }
}

Using the Component with a Callback

Alternatively, pass a Callback as the onclick prop.

use leptos::prelude::*;
use leptos_maybe_callback::MaybeCallback;

/// Parent component using `Button` with a `Callback`.
#[component]
#[allow(non_snake_case)]
pub fn ButtonWithCallback() -> impl IntoView {
    let on_click = Callback::new(|event: MouseEvent| {
        log::info!("Clicked with event: {:?}", event);
    });

    view! {
        <div>
            <Button onclick=on_click />
            <Button />
        </div>
    }
}

Omitting the Callback

If no callback is needed, omit the onclick prop or pass None.

use leptos::prelude::*;
use leptos_maybe_callback::MaybeCallback;

/// Parent component using `Button` without a callback.
#[component]
#[allow(non_snake_case)]
pub fn ButtonWithoutCallback() -> impl IntoView {
    view! {
        <div>
            <Button />
            <Button onclick=None />
        </div>
    }
}

Documentation

Comprehensive (WIP + TBD) documentation is available on docs.rs.

Testing

Run the test suite with:

cargo test

Contributing

Contributions are welcome! Please submit pull requests or open issues on GitHub.

Credits

The initial idea and implementation of MaybeCallback were contributed by @israelbarbara on Discord ( 26/12/2024). @geoffreygarrett facilitated its integration into the RustForWeb project.

Rust For Web

Part of the Rust For Web initiative to create and port web UI libraries for Rust. All projects are free and open source.

Dependencies

~23–34MB
~530K SLoC