Skip to main content

dioxus_bootstrap_css/
list_group.rs

1use dioxus::prelude::*;
2
3use crate::types::Color;
4
5/// Bootstrap ListGroup component.
6///
7/// ```rust
8/// rsx! {
9///     ListGroup {
10///         ListGroupItem { "Item 1" }
11///         ListGroupItem { active: true, "Item 2 (active)" }
12///         ListGroupItem { color: Color::Danger, "Item 3 (danger)" }
13///     }
14/// }
15/// ```
16#[derive(Clone, PartialEq, Props)]
17pub struct ListGroupProps {
18    /// Remove borders and rounded corners for use inside cards.
19    #[props(default)]
20    pub flush: bool,
21    /// Use numbered list style.
22    #[props(default)]
23    pub numbered: bool,
24    /// Additional CSS classes.
25    #[props(default)]
26    pub class: String,
27    /// Child elements (ListGroupItem components).
28    pub children: Element,
29}
30
31#[component]
32pub fn ListGroup(props: ListGroupProps) -> Element {
33    let mut classes = vec!["list-group".to_string()];
34    if props.flush {
35        classes.push("list-group-flush".to_string());
36    }
37    if props.numbered {
38        classes.push("list-group-numbered".to_string());
39    }
40    if !props.class.is_empty() {
41        classes.push(props.class.clone());
42    }
43    let full_class = classes.join(" ");
44
45    if props.numbered {
46        rsx! {
47            ol { class: "{full_class}", {props.children} }
48        }
49    } else {
50        rsx! {
51            ul { class: "{full_class}", {props.children} }
52        }
53    }
54}
55
56/// Bootstrap ListGroupItem component.
57#[derive(Clone, PartialEq, Props)]
58pub struct ListGroupItemProps {
59    /// Active state.
60    #[props(default)]
61    pub active: bool,
62    /// Disabled state.
63    #[props(default)]
64    pub disabled: bool,
65    /// Item color variant.
66    #[props(default)]
67    pub color: Option<Color>,
68    /// Click event handler. When set, renders as a button for interactivity.
69    #[props(default)]
70    pub onclick: Option<EventHandler<MouseEvent>>,
71    /// Additional CSS classes.
72    #[props(default)]
73    pub class: String,
74    /// Child elements.
75    pub children: Element,
76}
77
78#[component]
79pub fn ListGroupItem(props: ListGroupItemProps) -> Element {
80    let mut classes = vec!["list-group-item".to_string()];
81    if props.active {
82        classes.push("active".to_string());
83    }
84    if props.disabled {
85        classes.push("disabled".to_string());
86    }
87    if let Some(ref c) = props.color {
88        classes.push(format!("list-group-item-{c}"));
89    }
90    if props.onclick.is_some() {
91        classes.push("list-group-item-action".to_string());
92    }
93    if !props.class.is_empty() {
94        classes.push(props.class.clone());
95    }
96    let full_class = classes.join(" ");
97
98    if let Some(handler) = &props.onclick {
99        let handler = *handler;
100        rsx! {
101            button {
102                class: "{full_class}",
103                r#type: "button",
104                disabled: props.disabled,
105                onclick: move |evt| handler.call(evt),
106                {props.children}
107            }
108        }
109    } else {
110        rsx! {
111            li { class: "{full_class}", {props.children} }
112        }
113    }
114}