Components

Button

Documentation

Buttons are for clicking and doing button things

use leptos::children::Children;
use leptos::html;
use leptos::prelude::*;
use leptos::web_sys::MouseEvent;
use tailwind_fuse::*;

#[derive(TwClass)]
#[tw(
    class = "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0"
)]
struct ButtonStyle {
    variant: ButtonVariant,
    size: ButtonSize,
}

#[derive(TwVariant)]
pub enum ButtonVariant {
    #[tw(
        default,
        class = "bg-primary text-primary-foreground hover:bg-primary/90"
    )]
    Default,
    #[tw(class = "bg-destructive text-destructive-foreground hover:bg-destructive/90")]
    Destructive,
    #[tw(class = "border border-input bg-background hover:bg-accent hover:text-accent-foreground")]
    Outline,
    #[tw(class = "bg-secondary text-secondary-foreground hover:bg-secondary/80")]
    Secondary,
    #[tw(class = "hover:bg-accent hover:text-accent-foreground")]
    Ghost,
    #[tw(class = "text-primary underline-offset-4 hover:underline")]
    Link,
}

#[derive(TwVariant)]
pub enum ButtonSize {
    #[tw(default, class = "h-10 px-4 py-2")]
    Default,
    #[tw(class = "h-8 px-3 py-1")]
    Sm,
    #[tw(class = "h-12 px-6 py-3")]
    Lg,
    #[tw(class = "h-10 w-10 p-2")]
    Icon,
}

#[component]
pub fn Button(
    #[prop(optional)] class: &'static str,
    #[prop(optional)] variant: ButtonVariant,
    #[prop(optional)] size: ButtonSize,
    // TODO: add support for behaviour like @radix-ui/react-slot?
    // #[prop(optional)] as_child: bool,
    children: Children,
) -> impl IntoView {
    let final_class = ButtonStyle { variant, size }.with_class(class);
    let element: NodeRef<html::Button> = NodeRef::new();

    let on_click = move |e: MouseEvent| {
        element.get().map(|el| el.dispatch_event(&e));
    };

    view! {
        <button on:click=on_click node_ref=element class=final_class>
            {children()}
        </button>
    }
}
Click to expand