Button

Rust UI component that displays a button or a component that looks like a button.

button
  • Rust UI Icons - CopyCopy Demo
use leptos::prelude::*;

use crate::components::ui::button::Button;

#[component]
pub fn DemoButton() -> impl IntoView {
    view! { <Button>"Button"</Button> }
}

Installation

You can run either of the following commands:

# cargo install ui-cli --force
ui add demo_button
ui add button

Update the imports to match your project setup.

Copy and paste the following code into your project:

components/ui/button.rs

use leptos::prelude::*;
use leptos_ui::variants;

// TODO 💪 Loading state (demo_use_timeout_fn.rs and demo_button.rs)

variants! {
    Button {
        base: "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive  w-fit  hover:cursor-pointer", // Using hover:cursor-pointer as workaround for href_support.
        variants: {
            variant: {
                Default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
                Destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
                Outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/5",
                Secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
                Ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
                Accent: "bg-accent text-accent-foreground hover:bg-accent/80",
                Link: "text-primary underline-offset-4 hover:underline",
                //
                Warning: "bg-warning text-warning-foreground hover:bg-warning/90",
                Success: "bg-success text-success-foreground hover:bg-success/90",
                Bordered: "bg-transparent border border-zinc-200 text-muted-foreground",
            },
            size: {
                Default: "h-9 px-4 py-2 has-[>svg]:px-3",
                Sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
                Lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
                Icon: "size-9",
                //
                Mobile: "px-6 py-3 rounded-[24px]",
                Badge: "px-2.5 py-0.5 text-xs"
            }
        },
        component: {
            element: button,
            href_support: true
        }
    }
}

Update the imports to match your project setup.

Usage

use crate::components::ui::button::Button;
<Button>"Click me"</Button>

Examples

1. Reactive Button

The Button component can be reactive.

  • Rust UI Icons - CopyCopy Demo
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

  • Rust UI Icons - CopyCopy Demo
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

  • Rust UI Icons - CopyCopy Demo
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

  • Rust UI Icons - CopyCopy Demo
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

  • Rust UI Icons - CopyCopy Demo
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

  • Rust UI Icons - CopyCopy Demo
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>
    }
}

7. Split Button

A split button combines a primary action with a dropdown menu for additional options.

  • Rust UI Icons - CopyCopy Demo
Copy Options
use icons::{ChevronDown, Copy};
use leptos::prelude::*;

use crate::components::_coming_soon::dropdown_menu::{
    DropdownMenu, DropdownMenuAction, DropdownMenuAlign, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem,
    DropdownMenuLabel, DropdownMenuLink, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubItem,
    DropdownMenuSubTrigger, DropdownMenuTrigger,
};
use crate::components::ui::separator::Separator;
use crate::components::ui::split_button::{SplitButton, SplitButtonAction};

#[component]
pub fn DemoSplitButton() -> impl IntoView {
    view! {
        <SplitButton>
            <SplitButtonAction class="rounded-r-none rounded-l-md">
                <Copy class="size-3" />
                <span>"Copy Page"</span>
            </SplitButtonAction>

            <DropdownMenu align=DropdownMenuAlign::End>
                <DropdownMenuTrigger class="flex items-center px-1.5 h-8 rounded-l-none rounded-r-md border border-l transition-colors duration-150 outline-none bg-card text-card-foreground hover:bg-accent hover:text-accent-foreground active:bg-muted">
                    <ChevronDown class="size-3" />
                </DropdownMenuTrigger>

                <DropdownMenuContent>
                    <DropdownMenuLabel>"Copy Options"</DropdownMenuLabel>

                    <DropdownMenuGroup>
                        <DropdownMenuItem>
                            <DropdownMenuLink href="#">"Copy as HTML"</DropdownMenuLink>
                        </DropdownMenuItem>
                        <DropdownMenuItem>
                            <DropdownMenuLink href="#">"Copy as Markdown"</DropdownMenuLink>
                        </DropdownMenuItem>
                        <DropdownMenuItem>
                            <DropdownMenuAction>"Copy as Plain Text"</DropdownMenuAction>
                        </DropdownMenuItem>
                    </DropdownMenuGroup>

                    <Separator class="my-1" />

                    <DropdownMenuGroup>
                        <DropdownMenuSub>
                            <DropdownMenuSubTrigger>"Advanced Options"</DropdownMenuSubTrigger>
                            <DropdownMenuSubContent>
                                <DropdownMenuSubItem>"Copy with Formatting"</DropdownMenuSubItem>
                                <DropdownMenuSubItem>"Copy Structure Only"</DropdownMenuSubItem>
                                <DropdownMenuSubItem>"Copy with Metadata"</DropdownMenuSubItem>
                            </DropdownMenuSubContent>
                        </DropdownMenuSub>
                    </DropdownMenuGroup>
                </DropdownMenuContent>
            </DropdownMenu>
        </SplitButton>
    }
}

8. With Href

Automatic conversion to a tag with data-slot attribute.

  • Rust UI Icons - CopyCopy Demo
use leptos::prelude::*;

use crate::components::ui::button::{Button, ButtonVariant};

#[component]
pub fn DemoButtonHref() -> impl IntoView {
    view! {
        <div class="flex gap-10 p-4 rounded-lg border">
            <Button href="/dashboard">"Go to Dashboard"</Button>
            <Button href="/dashboard" variant=ButtonVariant::Ghost class="border-2 border-dashed">
                "Go to Dashboard (custom)"
            </Button>
            <Button href="https://ever-ui.com/" rel="noopener" target="_blank">
                "External Link"
            </Button>
        </div>
    }
}