Skip to main content

dioxus_bootstrap_css/
button.rs

1use dioxus::prelude::*;
2
3use crate::types::{Color, Size};
4
5/// Bootstrap Button component.
6///
7/// ```rust
8/// rsx! {
9///     Button { color: Color::Primary, "Click me" }
10///     Button { color: Color::Danger, outline: true, size: Size::Sm, "Delete" }
11///     Button { color: Color::Success, disabled: true, "Saved" }
12/// }
13/// ```
14#[derive(Clone, PartialEq, Props)]
15pub struct ButtonProps {
16    /// Button color variant.
17    #[props(default)]
18    pub color: Color,
19    /// Use outline style instead of filled.
20    #[props(default)]
21    pub outline: bool,
22    /// Button size.
23    #[props(default)]
24    pub size: Size,
25    /// Whether the button is disabled.
26    #[props(default)]
27    pub disabled: bool,
28    /// HTML button type attribute.
29    #[props(default = "button".to_string())]
30    pub r#type: String,
31    /// Click event handler.
32    #[props(default)]
33    pub onclick: Option<EventHandler<MouseEvent>>,
34    /// Additional CSS classes.
35    #[props(default)]
36    pub class: String,
37    /// Child elements.
38    pub children: Element,
39}
40
41#[component]
42pub fn Button(props: ButtonProps) -> Element {
43    let style = if props.outline { "btn-outline" } else { "btn" };
44    let color = props.color;
45    let color_class = format!("{style}-{color}");
46
47    let size_class = match props.size {
48        Size::Md => String::new(),
49        s => format!(" btn-{s}"),
50    };
51
52    let full_class = if props.class.is_empty() {
53        format!("btn {color_class}{size_class}")
54    } else {
55        format!("btn {color_class}{size_class} {}", props.class)
56    };
57
58    rsx! {
59        button {
60            class: "{full_class}",
61            r#type: "{props.r#type}",
62            disabled: props.disabled,
63            onclick: move |evt| {
64                if let Some(handler) = &props.onclick {
65                    handler.call(evt);
66                }
67            },
68            {props.children}
69        }
70    }
71}
72
73/// Bootstrap ButtonGroup component.
74///
75/// ```rust
76/// rsx! {
77///     ButtonGroup {
78///         Button { color: Color::Primary, "Left" }
79///         Button { color: Color::Primary, "Middle" }
80///         Button { color: Color::Primary, "Right" }
81///     }
82/// }
83/// ```
84#[derive(Clone, PartialEq, Props)]
85pub struct ButtonGroupProps {
86    /// Button group size.
87    #[props(default)]
88    pub size: Size,
89    /// Additional CSS classes.
90    #[props(default)]
91    pub class: String,
92    /// Child elements (buttons).
93    pub children: Element,
94}
95
96#[component]
97pub fn ButtonGroup(props: ButtonGroupProps) -> Element {
98    let size_class = match props.size {
99        Size::Md => String::new(),
100        s => format!(" btn-group-{s}"),
101    };
102
103    let full_class = if props.class.is_empty() {
104        format!("btn-group{size_class}")
105    } else {
106        format!("btn-group{size_class} {}", props.class)
107    };
108
109    rsx! {
110        div {
111            class: "{full_class}",
112            role: "group",
113            {props.children}
114        }
115    }
116}