Attribute Macro leptos::slot

source ·
#[slot]
Expand description

Annotates a struct so that it can be used with your Component as a slot.

The #[slot] macro allows you to annotate plain Rust struct as component slots and use them within your Leptos component properties. The struct can contain any number of fields. When you use the component somewhere else, the names of the slot fields are the names of the properties you use in the view macro.

Here’s how you would define and use a simple Leptos component which can accept a custom slot:

use std::time::Duration;

#[slot]
struct HelloSlot {
    // Same prop syntax as components.
    #[prop(optional)]
    children: Option<Children>,
}

#[component]
fn HelloComponent(
     
    /// Component slot, should be passed through the <HelloSlot slot> syntax.
    hello_slot: HelloSlot,
) -> impl IntoView {
    // mirror the children from the slot, if any were passed
    if let Some(children) = hello_slot.children {
        (children)().into_view()
    } else {
        ().into_view()
    }
}

#[component]
fn App() -> impl IntoView {
    view! {
        <HelloComponent>
            <HelloSlot slot>
                "Hello, World!"
            </HelloSlot>
        </HelloComponent>
    }
}

/// Here are some important details about how slots work within the framework:

  1. Most of the same rules from component macro should also be followed on slots.

  2. Specifying only slot without a name (such as in <HelloSlot slot>) will default the chosen slot to the a snake case version of the slot struct name (hello_slot for <HelloSlot>).

  3. Event handlers cannot be specified directly on the slot.

// ❌ This won't work
# use leptos::*;

#[slot]
struct SlotWithChildren {
    children: Children,
}

#[component]
fn ComponentWithSlot(slot: SlotWithChildren) -> impl IntoView {
    (slot.children)()
}

#[component]
fn App() -> impl IntoView {
    view! {
        <ComponentWithSlot>
          <SlotWithChildren slot:slot on:click=move |_| {}>
            <h1>"Hello, World!"</h1>
          </SlotWithChildren>
        </ComponentWithSlot>
    }
}
// ✅ Do this instead

#[slot]
struct SlotWithChildren {
    children: Children,
}

#[component]
fn ComponentWithSlot(slot: SlotWithChildren) -> impl IntoView {
    (slot.children)()
}

#[component]
fn App() -> impl IntoView {
    view! {
        <ComponentWithSlot>
          <SlotWithChildren slot:slot>
            <div on:click=move |_| {}>
              <h1>"Hello, World!"</h1>
            </div>
          </SlotWithChildren>
        </ComponentWithSlot>
    }
}