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