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    /// 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}