dioxus_bootstrap_css/
accordion.rs1use dioxus::prelude::*;
2
3#[derive(Clone, PartialEq, Props)]
19pub struct AccordionProps {
20 pub open: Signal<Option<usize>>,
23 #[props(default)]
25 pub flush: bool,
26 #[props(default)]
28 pub class: String,
29 pub children: Element,
31}
32
33#[component]
34pub fn Accordion(props: AccordionProps) -> Element {
35 let flush = if props.flush { " accordion-flush" } else { "" };
36 let full_class = if props.class.is_empty() {
37 format!("accordion{flush}")
38 } else {
39 format!("accordion{flush} {}", props.class)
40 };
41
42 rsx! {
43 div { class: "{full_class}", {props.children} }
44 }
45}
46
47#[derive(Clone, PartialEq, Props)]
49pub struct AccordionItemProps {
50 pub index: usize,
52 pub title: String,
54 pub open: Signal<Option<usize>>,
56 #[props(default)]
58 pub class: String,
59 pub children: Element,
61}
62
63#[component]
64pub fn AccordionItem(props: AccordionItemProps) -> Element {
65 let is_open = *props.open.read() == Some(props.index);
66 let mut open_signal = props.open;
67 let index = props.index;
68
69 let button_class = if is_open {
70 "accordion-button"
71 } else {
72 "accordion-button collapsed"
73 };
74
75 let body_class = if is_open {
76 "accordion-collapse collapse show"
77 } else {
78 "accordion-collapse collapse"
79 };
80
81 let full_class = if props.class.is_empty() {
82 "accordion-item".to_string()
83 } else {
84 format!("accordion-item {}", props.class)
85 };
86
87 rsx! {
88 div { class: "{full_class}",
89 h2 { class: "accordion-header",
90 button {
91 class: "{button_class}",
92 r#type: "button",
93 "aria-expanded": if is_open { "true" } else { "false" },
94 onclick: move |_| {
95 if is_open {
96 open_signal.set(None);
97 } else {
98 open_signal.set(Some(index));
99 }
100 },
101 "{props.title}"
102 }
103 }
104 div { class: "{body_class}",
105 div { class: "accordion-body",
106 {props.children}
107 }
108 }
109 }
110 }
111}