Button
Rust UI component that displays a button or a component that looks like a button.
button
use leptos::prelude::*; use crate::components::ui::button::Button; #[component] pub fn DemoButton() -> impl IntoView { view! { <Button>"Button"</Button> } }
Demos
1. Reactive Button
The Button
component can be reactive.
use leptos::prelude::*; use crate::components::ui::button::Button; #[component] pub fn DemoButtonReactive() -> impl IntoView { let count = RwSignal::new(0); let increment = move |_| *count.write() += 1; view! { <Button on:click=increment>"Click Me: " {count}</Button> } }
2. Variants
use leptos::prelude::*; use crate::components::ui::button::{Button, ButtonVariant}; #[component] pub fn DemoButtonVariants() -> impl IntoView { view! { <div class="flex flex-col gap-4 items-center md:flex-row"> <Button>Default</Button> <Button variant=ButtonVariant::Secondary>Secondary</Button> <Button variant=ButtonVariant::Outline>Outline</Button> <Button variant=ButtonVariant::Ghost>Ghost</Button> <Button variant=ButtonVariant::Destructive>Destructive</Button> </div> } }
3. Sizes
use leptos::prelude::*; use crate::components::ui::button::{Button, ButtonSize}; #[component] pub fn DemoButtonSizes() -> impl IntoView { view! { <div class="flex gap-4"> <Button size=ButtonSize::Sm>Small</Button> <Button>Default</Button> <Button size=ButtonSize::Lg>Large</Button> </div> } }
4. Disabled
use leptos::prelude::*; use crate::components::ui::button::Button; #[component] pub fn DemoButtonDisabled() -> impl IntoView { view! { <div class="flex gap-4"> <Button>"Normal"</Button> <Button disabled=true>"Disabled"</Button> </div> } }
5. Overriding Button
use leptos::prelude::*; use crate::components::ui::button::Button; #[component] pub fn DemoButtonOverride() -> impl IntoView { view! { <Button class="hover:bg-pink-500 bg-sky-500">Fancy Button</Button> } }
6. Button with Clx
use leptos::prelude::*; use leptos_ui::clx; // * 💁 Define your reusable Component here: clx! {MyButton, button, "px-4 py-2 bg-neutral-900 text-white rounded-md"} /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ✨ FUNCTIONS ✨ */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ #[component] pub fn DemoButtonWithClx() -> impl IntoView { let count = RwSignal::new(0); let on_click = move |_| *count.write() += 1; view! { <MyButton class="bg-sky-500" on:click=on_click> "Click Me: " {count} </MyButton> } }
Installation
You can run either of the following commands:
# cargo install ui-cli --forceui add demo_buttonui add button
Update the imports to match your project setup.
Copy and paste the following code into your project:
components/ui/button.rs
#![allow(dead_code)] use leptos::prelude::*; use tw_merge::*; // TODO 💪 Loading state (demo_use_timeout_fn.rs and demo_button.rs) #[component] pub fn Button( #[prop(into, optional)] variant: Signal<ButtonVariant>, #[prop(into, optional)] size: Signal<ButtonSize>, #[prop(into, optional)] class: Signal<String>, #[prop(into, optional)] id: Signal<String>, #[prop(into, optional)] formmethod: Signal<String>, #[prop(into, optional)] value: Signal<String>, #[prop(into, optional)] role: Signal<String>, #[prop(into, optional)] disabled: Signal<bool>, #[prop(into, optional)] r#type: Signal<String>, #[prop(into, optional)] style: Option<String>, #[prop(into, optional)] onclick: Option<String>, // #[prop(into, optional)] popovertarget: Signal<String>, // #[prop(into, optional)] popovertargetaction: Signal<String>, // children: Children, ) -> impl IntoView { let class = Memo::new(move |_| { let variant = variant.get(); let size = size.get(); let button = ButtonClass { variant, size }; button.with_class(class.get()) }); view! { <button // class=class disabled=disabled id=id role=role type=r#type formmethod=formmethod value=value style=style onclick=onclick > // popovertarget=popovertarget/ // popovertargetaction=popovertargetaction {children()} </button> } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 🧬 STRUCT 🧬 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ #[derive(TwClass, Default)] #[tw( class = "inline-flex justify-center items-center text-sm font-medium whitespace-nowrap rounded-md transition-colors w-fit focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50" )] pub struct ButtonClass { 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-secondary text-secondary-foreground hover:bg-secondary/80")] Secondary, #[tw(class = "bg-accent text-accent-foreground hover:bg-accent/80")] Accent, #[tw(class = "bg-destructive text-destructive-foreground hover:bg-destructive/90")] Destructive, #[tw(class = "bg-warning text-warning-foreground hover:bg-warning/90")] Warning, #[tw(class = "bg-success text-success-foreground hover:bg-success/90")] Success, #[tw(class = "border bg-background border-input hover:bg-accent hover:text-accent-foreground")] Outline, #[tw(class = "bg-transparent border border-zinc-200 text-muted-foreground")] Bordered, // TODO. Improve this variant. #[tw(class = "hover:bg-accent hover:text-accent-foreground")] Ghost, #[tw(class = "underline-offset-4 hover:underline")] Link, } #[derive(TwVariant)] pub enum ButtonSize { #[tw(default, class = "px-4 py-2 h-9")] Default, #[tw(class = "px-3 h-8")] Sm, #[tw(class = "px-8 h-10")] Lg, #[tw(class = "size-8")] Icon, #[tw(class = "px-6 py-3 rounded-[24px]")] Mobile, }
Update the imports to match your project setup.
Usage
// Coming soon 🦀