Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ exclude = ["/assets", "/examples"]
yew = { version = "0.21.0", default-features = false, optional = true }
dioxus = { version = "0.6.3", optional = true }
leptos = { version = "0.7.7", optional = true }
web-sys = { version = "0.3.77", features = ["Window"]}
gloo-timers = "0.3.0"
web-sys = { version = "0.3.77", features = ["Window", "UrlSearchParams", "Url"]}
gloo-timers = { version = "0.3.0", optional = true }

[features]
yew = ["dep:yew"]
yew = ["dep:yew", "gloo-timers"]
dio = ["dioxus"]
lep = ["leptos"]

Expand Down
159 changes: 159 additions & 0 deletions DIOXUS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# 🧬 Table RS Dioxus Usage

Adding Table RS to your project is simple:

1. Make sure your project is set up with **Dioxus**. Refer to the [Dioxus Getting Started Guide](https://dioxuslabs.com/learn/0.6/getting_started) for setup instructions.

1. Add the **table-rs** library to your dependencies by including it in your `Cargo.toml` file:

```sh
cargo add table-rs --features=dio
```

1. Import the `Table` component into your Dioxus application.

## 🛠️ Usage

Incorporating Table RS into your Dioxus app involves just a few steps:

1. Import the `Table` component and types:

```rust
use dioxus::prelude::*;
use table_rs::dioxus::table::Table;
use table_rs::dioxus::types::Column;
use maplit::hashmap;
```

1. Use the `Table` component in your Dioxus app:

```rust
use dioxus::prelude::*;
use table_rs::dioxus::table::Table;
use table_rs::dioxus::types::Column;
use maplit::hashmap;


fn App() -> Element {
let data = vec![
hashmap! { "name" => "Ferris".to_string(), "email" => "ferris@opensass.org".to_string() },
hashmap! { "name" => "Ferros".to_string(), "email" => "ferros@opensass.org".to_string() },
hashmap! { "name" => "Crab".to_string(), "email" => "crab@opensass.org".to_string() },
];

let columns = vec![
Column {
id: "name",
header: "Name",
sortable: true,
..Default::default()
},
Column {
id: "email",
header: "Email",
sortable: false,
..Default::default()
},
];

rsx! {
Table {
data: data,
columns: columns,
}
}
}
```

## 🔧 Props

### `Table` Component Props

| Prop | Type | Description | Default |
| ----------- | ------------------------------------- | --------------------------------- | ------- |
| `data` | `Vec<HashMap<&'static str, String>>` | The row data to render. | `[]` |
| `columns` | `Vec<Column>` | Column definitions. | `[]` |
| `page_size` | `usize` | Number of rows per page. | `10` |
| `loading` | `bool` | Show loading state if true. | `false` |
| `paginate` | `bool` | Enable pagination. | `false` |
| `search` | `bool` | Enable global search input. | `false` |
| `classes` | `TableClasses` | CSS class overrides. | Default |
| `styles` | `HashMap<&'static str, &'static str>` | Inline style overrides. | `{}` |
| `texts` | `TableTexts` | Text customization for UI labels. | Default |

### `Column` Props

| Prop | Type | Description | Default |
| ---------- | ---------------------- | ----------------------------------------- | --------------------------------------------------------- |
| `id` | `&'static str` | Column key (used to fetch from row data). | `""` |
| `header` | `&'static str` | Display name in the table header. | `""` |
| `sortable` | `bool` | Allow sorting on this column. | `false` |
| `style` | `Option<&'static str>` | Inline CSS for the header. | Some("padding: 8px; font-weight: 600; text-align: left;") |
| `class` | `Option<&'static str>` | Optional class name for this column. | Some("table-header-cell") |

### `TableClasses`

| Prop | Type | Description | Default |
| ------------------- | -------------- | ------------------------------------ | ----------------------- |
| `container` | `&'static str` | Outer container class. | `"table-container"` |
| `table` | `&'static str` | Main table class. | `"table"` |
| `thead` | `&'static str` | Table head (`<thead>`) class. | `"thead"` |
| `tbody` | `&'static str` | Table body (`<tbody>`) class. | `"tbody"` |
| `row` | `&'static str` | Row (`<tr>`) class. | `"tr"` |
| `header_cell` | `&'static str` | Header cell (`<th>`) class. | `"th"` |
| `body_cell` | `&'static str` | Body cell (`<td>`) class. | `"td"` |
| `loading_row` | `&'static str` | Row shown when loading. | `"loading-row"` |
| `empty_row` | `&'static str` | Row shown when no data is available. | `"empty-row"` |
| `search_input` | `&'static str` | Search input field class. | `"search-input"` |
| `pagination` | `&'static str` | Pagination controls wrapper. | `"pagination-controls"` |
| `pagination_button` | `&'static str` | Pagination buttons. | `"pagination-button"` |

### `TableTexts`

| Prop | Type | Description | Default |
| -------------------- | -------------- | --------------------------------- | ----------------------------- |
| `loading` | `&'static str` | Text shown when loading. | `"Loading..."` |
| `empty` | `&'static str` | Text when no data is present. | `"No results found"` |
| `search_placeholder` | `&'static str` | Placeholder for search input. | `"Search..."` |
| `previous_button` | `&'static str` | Label for previous page button. | `"Previous"` |
| `next_button` | `&'static str` | Label for next page button. | `"Next"` |
| `page_indicator` | `&'static str` | Format string for page indicator. | `"Page {current} of {total}"` |

### 🧱 Style/Layout Structure

```sh
+-------------------------------------------------------------+
| [container] | <-- class: "table-container"
| |
| +-----------------------------------------------------+ |
| | [search_input] | | <-- class: "search-input"
| | (optional search <input> element) | |
| +-----------------------------------------------------+ |
| |
| +-----------------------------------------------------+ |
| | [table] | | <-- class: "table"
| | +--------------------[thead]--------------------+ | | <-- class: "thead"
| | | Column Headers (e.g., Name, Email) | | |
| | +-----------------------------------------------+ | |
| | +--------------------[tbody]--------------------+ | | <-- class: "tbody"
| | | Data rows (from `data` prop, each row = <tr>)| | |
| | +-----------------------------------------------+ | |
| +-----------------------------------------------------+ |
| |
| +-----------------------------------------------------+ |
| | [pagination] | | <-- class: "pagination-controls"
| | Page selector / next-prev buttons (if enabled) | |
| +-----------------------------------------------------+ |
+-------------------------------------------------------------+
```

## 💡 Notes

- The `data` must match the `id` values defined in each `Column`.
- The `search` prop enables input-based filtering across all columns.
- Pagination is controlled using the `page_size` and `paginate` props.
- Sorting is column-specific via `sortable = true` and `on_sort_column`.
- All style classes can be customized via `TableClasses`.
- All texts are configurable via `TableTexts`.
- The component handles loading and empty states out-of-the-box.
- You can inject additional per-column styling via `Column.style` and `Column.class`.
33 changes: 2 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
| Framework | Live Demo |
| --------- | ------------------------------------------------------------------------------------------------------------------------ |
| Yew | [![Netlify Status](https://api.netlify.com/api/v1/badges/4e1494d6-c19a-4a4c-b2d3-47d964214a71/deploy-status)](https://table-rs.netlify.app) |
| Dioxus | TODO |
| Dioxus | [![Netlify Status](https://api.netlify.com/api/v1/badges/4e1494d6-c19a-4a4c-b2d3-47d964214a71/deploy-status)](https://table-dio.netlify.app) |
| Leptos | TODO |

## 📜 Intro
Expand All @@ -44,7 +44,7 @@ The following are some of the reasons why **Table RS** should be your go-to tabl
<!-- absolute url for docs.rs cause YEW.md is not included in crate -->
Refer to [our guide](https://github.com/opensass/table-rs/blob/main/YEW.md) to integrate this component into your Yew app.

## 🧬 Dioxus Usage (TODO)
## 🧬 Dioxus Usage

<!-- absolute url for docs.rs cause DIOXUS.md is not included in crate -->
Refer to [our guide](https://github.com/opensass/table-rs/blob/main/DIOXUS.md) to integrate this component into your Dioxus app.
Expand All @@ -54,35 +54,6 @@ Refer to [our guide](https://github.com/opensass/table-rs/blob/main/DIOXUS.md) t
<!-- absolute url for docs.rs cause LEPTOS.md is not included in crate -->
Refer to [our guide](https://github.com/opensass/table-rs/blob/main/LEPTOS.md) to integrate this component into your Leptos app.

## 📊 Benchmark: TanStack Table vs Table RS

| Metric | TanStack Table (React) | Table RS (Yew + WASM) |
|--------------------------------|-----------------------------|----------------------------|
| **Page Load Time (1M rows)** | ~10 seconds | ~2 seconds |
| **Memory Heap Usage** | >3 GB (heap overflow) | ~1.1 GB (stable) |
| **Initial Rendering** | Heavy blocking, slow DOM paint | Efficient, lightweight rendering |
| **Browser Responsiveness** | Delayed interactivity | Smooth after hydration |
| **Sorting Performance** | 2-4s for large columns | Sub-1s due to WASM speed |
| **Search Performance** | Acceptable, but slower | Instantaneous, even at scale |
| **Lighthouse Performance Score** | 49/100 | 60/100 |
| **Scalability** | Limited due to memory and VDOM | Near-native scalability |

### 🟨 TanStack Table (React)
- Uses Virtual DOM and JS heap to manage massive data.
- Runtime bottlenecks emerge with >100k rows.
- Memory allocation during sorting and filtering can spike to **3GB+**, often leading to **heap overflow** during intensive usage.
- Lighthouse audit shows poor TTI and CPU blocking.

### 🟩 Table RS (Yew + WASM)
- WASM-compiled logic is highly memory-efficient and deterministic.
- DOM rendering is direct, bypassing React's reconciliation.
- ~1.1 GB of memory heap used even with **1 million rows**.
- Built-in support for search/sort with stable paging.
- No hydration issues (client-only generation).
- Lighthouse performance significantly better, especially in CPU/Memory metrics.

For large-data UI benchmarks like tables with millions of rows, **`table-rs` in Yew/WASM is a superior choice** compared to React + TanStack.

## 🤝 Contributions

Contributions are welcome! Whether it's bug fixes, feature requests, or examples, we would love your help to make **Table RS** even better.
Expand Down
Loading