dioxus_bootstrap_css/table.rs
1use dioxus::prelude::*;
2
3use crate::types::{Color, Size};
4
5/// Bootstrap Table component.
6///
7/// # Bootstrap HTML → Dioxus
8///
9/// ```html
10/// <!-- Bootstrap HTML -->
11/// <div class="table-responsive">
12/// <table class="table table-striped table-hover">
13/// <caption>List of users</caption>
14/// <thead><tr><th>Name</th><th>Role</th></tr></thead>
15/// <tbody><tr><td>Alice</td><td>Admin</td></tr></tbody>
16/// </table>
17/// </div>
18/// ```
19///
20/// ```rust,no_run
21/// // Dioxus equivalent
22/// rsx! {
23/// Table { striped: true, hover: true, responsive: true,
24/// caption: "List of users", caption_top: true,
25/// thead {
26/// tr { th { "Name" } th { "Role" } }
27/// }
28/// tbody {
29/// tr { td { "Alice" } td { "Admin" } }
30/// }
31/// }
32/// }
33/// ```
34///
35/// # Props
36///
37/// - `striped` — striped rows
38/// - `striped_columns` — striped columns instead of rows
39/// - `hover` — highlight rows on hover
40/// - `bordered` — borders on all cells
41/// - `responsive` — horizontal scroll wrapper
42/// - `caption` / `caption_top` — table caption text and position
43/// - `size` — `Size::Sm` for compact table
44/// - `color` — table color variant
45#[derive(Clone, PartialEq, Props)]
46pub struct TableProps {
47 /// Striped rows.
48 #[props(default)]
49 pub striped: bool,
50 /// Striped columns instead of rows.
51 #[props(default)]
52 pub striped_columns: bool,
53 /// Highlight rows on hover.
54 #[props(default)]
55 pub hover: bool,
56 /// Add borders to all cells.
57 #[props(default)]
58 pub bordered: bool,
59 /// Remove all borders.
60 #[props(default)]
61 pub borderless: bool,
62 /// Compact table with smaller padding.
63 #[props(default)]
64 pub size: Size,
65 /// Table color variant.
66 #[props(default)]
67 pub color: Option<Color>,
68 /// Wrap in a responsive container for horizontal scrolling.
69 #[props(default)]
70 pub responsive: bool,
71 /// Caption text (displayed above or below the table).
72 #[props(default)]
73 pub caption: String,
74 /// Place caption at the top (default is bottom per Bootstrap).
75 #[props(default)]
76 pub caption_top: bool,
77 /// Additional CSS classes.
78 #[props(default)]
79 pub class: String,
80 /// Child elements (thead, tbody, etc.).
81 pub children: Element,
82}
83
84#[component]
85pub fn Table(props: TableProps) -> Element {
86 let mut classes = vec!["table".to_string()];
87
88 if props.striped {
89 classes.push("table-striped".to_string());
90 }
91 if props.striped_columns {
92 classes.push("table-striped-columns".to_string());
93 }
94 if props.caption_top {
95 classes.push("caption-top".to_string());
96 }
97 if props.hover {
98 classes.push("table-hover".to_string());
99 }
100 if props.bordered {
101 classes.push("table-bordered".to_string());
102 }
103 if props.borderless {
104 classes.push("table-borderless".to_string());
105 }
106 if let Size::Sm = props.size {
107 classes.push("table-sm".to_string());
108 }
109 if let Some(ref c) = props.color {
110 classes.push(format!("table-{c}"));
111 }
112 if !props.class.is_empty() {
113 classes.push(props.class.clone());
114 }
115
116 let full_class = classes.join(" ");
117
118 let caption = props.caption.clone();
119
120 if props.responsive {
121 rsx! {
122 div { class: "table-responsive",
123 table { class: "{full_class}",
124 if !caption.is_empty() {
125 caption { "{caption}" }
126 }
127 {props.children}
128 }
129 }
130 }
131 } else {
132 rsx! {
133 table { class: "{full_class}",
134 if !caption.is_empty() {
135 caption { "{caption}" }
136 }
137 {props.children}
138 }
139 }
140 }
141}