Skip to main content

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}