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 /// Any additional HTML attributes.
81 #[props(extends = GlobalAttributes)]
82 attributes: Vec<Attribute>,
83 /// Child elements (thead, tbody, etc.).
84 pub children: Element,
85}
86
87#[component]
88pub fn Table(props: TableProps) -> Element {
89 let mut classes = vec!["table".to_string()];
90
91 if props.striped {
92 classes.push("table-striped".to_string());
93 }
94 if props.striped_columns {
95 classes.push("table-striped-columns".to_string());
96 }
97 if props.caption_top {
98 classes.push("caption-top".to_string());
99 }
100 if props.hover {
101 classes.push("table-hover".to_string());
102 }
103 if props.bordered {
104 classes.push("table-bordered".to_string());
105 }
106 if props.borderless {
107 classes.push("table-borderless".to_string());
108 }
109 if let Size::Sm = props.size {
110 classes.push("table-sm".to_string());
111 }
112 if let Some(ref c) = props.color {
113 classes.push(format!("table-{c}"));
114 }
115 if !props.class.is_empty() {
116 classes.push(props.class.clone());
117 }
118
119 let full_class = classes.join(" ");
120
121 let caption = props.caption.clone();
122
123 if props.responsive {
124 rsx! {
125 div { class: "table-responsive",
126 table { class: "{full_class}",
127 ..props.attributes,
128 if !caption.is_empty() {
129 caption { "{caption}" }
130 }
131 {props.children}
132 }
133 }
134 }
135 } else {
136 rsx! {
137 table { class: "{full_class}",
138 ..props.attributes,
139 if !caption.is_empty() {
140 caption { "{caption}" }
141 }
142 {props.children}
143 }
144 }
145 }
146}