Some checks are pending
Documentation Lint & Validation / Markdown Linting (push) Waiting to run
Documentation Lint & Validation / Validate mdBook Configuration (push) Waiting to run
Documentation Lint & Validation / Content & Structure Validation (push) Waiting to run
Documentation Lint & Validation / Lint & Validation Summary (push) Blocked by required conditions
mdBook Build & Deploy / Build mdBook (push) Waiting to run
mdBook Build & Deploy / Documentation Quality Check (push) Blocked by required conditions
mdBook Build & Deploy / Deploy to GitHub Pages (push) Blocked by required conditions
mdBook Build & Deploy / Notification (push) Blocked by required conditions
Rust CI / Security Audit (push) Waiting to run
Rust CI / Check + Test + Lint (nightly) (push) Waiting to run
Rust CI / Check + Test + Lint (stable) (push) Waiting to run
8.2 KiB
8.2 KiB
vapora-leptos-ui
Glassmorphism UI component library for Leptos 0.8.15+
Status: Functional with core components implemented. Suitable for internal use and projects willing to contribute.
Features
- 🎨 Glassmorphism design - Cyan/purple/pink gradients with backdrop blur
- 🔄 CSR/SSR agnostic - Components work in both client-side and server-side rendering contexts
- ♿ Accessible - ARIA labels, keyboard navigation (Modal), focus management (Modal)
- 📱 Mobile responsive - Tailwind-based responsive utilities
- 🎯 UnoCSS compatible - Works with build-time CSS generation
- 🧩 Reusable - Can be used in any Leptos 0.8+ project
Installation
[dependencies]
vapora-leptos-ui = { path = "../vapora-leptos-ui" }
leptos = "0.8.15"
Note: Not yet published to crates.io. Use as a path dependency or git dependency.
Quick Start
use leptos::prelude::*;
use vapora_leptos_ui::{Button, Input, Spinner, Variant, Size};
#[component]
fn App() -> impl IntoView {
view! {
<div class="p-6 space-y-4">
<Button variant=Variant::Primary size=Size::Large>
"Create Project"
</Button>
<Input
input_type="text"
placeholder="Enter your name..."
on_input=Callback::new(|_ev| {
// Handle input
})
/>
<Spinner size=Size::Medium />
</div>
}
}
Available Components
✅ Primitives (Fully Functional)
| Component | Description | Variants | Status |
|---|---|---|---|
| Button | Glassmorphism button | Primary, Secondary, Danger, Ghost | ✅ Complete |
| Input | Text input field | N/A | ✅ Complete |
| Badge | Status badge | Custom classes | ✅ Complete |
| Spinner | Loading animation | Small, Medium, Large | ✅ Complete |
✅ Layout (Fully Functional)
| Component | Description | Features | Status |
|---|---|---|---|
| Card | Container card | Glassmorphism, hoverable, glow colors | ✅ Complete |
| Modal | Dialog overlay | Portal, keyboard (Escape), focus trap, backdrop click | ✅ Complete |
✅ Data (Fully Functional)
| Component | Description | Features | Status |
|---|---|---|---|
| Table | Data table | Internal sorting, sortable columns | ✅ Complete |
| Pagination | Page controls | Current page, total pages, callbacks | ✅ Complete |
| StatCard | Metric display | Label, value, optional trend | ✅ Complete |
✅ Forms (Fully Functional)
| Component | Description | Features | Status |
|---|---|---|---|
| FormField | Form wrapper | Label, error display, help text, required indicator | ✅ Complete |
| Validation | Helper functions | validate_required, validate_email, validate_min_length, validate_max_length |
✅ Complete |
✅ Feedback (Fully Functional)
| Component | Description | Features | Status |
|---|---|---|---|
| ToastProvider | Toast context | Global notifications, auto-dismiss (3s) | ✅ Complete |
| use_toast() | Toast hook | Show success/error/info toasts | ✅ Complete |
✅ Navigation (Fully Functional)
| Component | Description | Features | Status |
|---|---|---|---|
| SpaLink | Client-side link | No page reload, external link detection | ✅ Complete |
🔧 Utilities
| Component | Description | Status |
|---|---|---|
| Portal | DOM portal | ✅ Complete (used by Modal) |
Theme System
use vapora_leptos_ui::{Variant, Size, BlurLevel, GlowColor};
// Visual variants
Variant::Primary // Cyan-purple gradient
Variant::Secondary // Transparent with border
Variant::Danger // Red gradient
Variant::Ghost // Subtle hover
// Size variants
Size::Small // px-3 py-1.5 text-sm
Size::Medium // px-4 py-2 text-base (default)
Size::Large // px-6 py-3 text-lg
// Backdrop blur levels
BlurLevel::None, Sm, Md, Lg, Xl
// Glow colors (for Card)
GlowColor::None, Cyan, Purple, Pink, Blue
Examples
See cookbook.md for comprehensive examples of each component.
Modal with Form
use vapora_leptos_ui::{Modal, FormField, Input, Button};
#[component]
fn CreateProject() -> impl IntoView {
let (show_modal, set_show_modal) = signal(false);
let (title, set_title) = signal(String::new());
view! {
<Button on_click=Callback::new(move |_| set_show_modal.set(true))>
"New Project"
</Button>
<Show when=move || show_modal.get()>
<Modal on_close=Callback::new(move |_| set_show_modal.set(false))>
<h2 class="text-2xl font-bold text-white mb-4">"Create Project"</h2>
<FormField label="Title".to_string() required=true>
<Input
placeholder="Project name"
on_input=Callback::new(move |ev| {
// Extract value from event
set_title.set(event_target_value(&ev));
})
/>
</FormField>
</Modal>
</Show>
}
}
Table with Pagination
use vapora_leptos_ui::{Table, TableColumn, Pagination};
#[component]
fn DataTable() -> impl IntoView {
let (current_page, set_current_page) = signal(1usize);
let items_per_page = 10;
let columns = vec![
TableColumn::new("Name", "name").sortable(),
TableColumn::new("Status", "status").sortable(),
TableColumn::new("Date", "date"),
];
// Paginate data
let total_pages = data.len().div_ceil(items_per_page);
let paginated_data = /* slice data for current page */;
view! {
<Table columns=columns rows=paginated_data />
{move || if total_pages > 1 {
view! {
<Pagination
current_page=current_page.get()
total_pages=total_pages
on_page_change=Callback::new(move |page| {
set_current_page.set(page);
})
/>
}
} else {
view! { <div /> }
}}
}
}
Architecture
This library follows the Rustelo pattern for CSR/SSR agnostic components:
component/
├── mod.rs # Module exports
├── unified.rs # Public API (delegates to client/ssr)
├── client.rs # WASM/interactive implementation
└── ssr.rs # Server-side static implementation
Components automatically select the correct implementation:
- WASM target (
wasm32-unknown-unknown): Usesclient.rswith full interactivity - Non-WASM target: Uses
ssr.rsfor static server-side rendering
Known Limitations
See limitations.md for detailed list of known issues and missing features.
Summary:
- No i18n support yet
- Table sorting is client-side only (no server-side sorting)
- Toast auto-dismiss timing is fixed (3 seconds)
- Input is uncontrolled (no
valueprop) - No Select, Textarea, Checkbox, Radio components yet
- No Dialog, ConfirmDialog components yet
Development
# Build component library (WASM target)
cargo build -p vapora-leptos-ui --target wasm32-unknown-unknown
# Run clippy (strict mode)
cargo clippy -p vapora-leptos-ui --target wasm32-unknown-unknown -- -D warnings
# Format code
cargo fmt -p vapora-leptos-ui
Contributing
This library is under active development. Contributions welcome:
- Check limitations.md for missing features
- Follow existing component patterns (unified/client/ssr)
- Ensure clippy passes with
-D warnings - Add examples to cookbook.md
License
Licensed under either of:
- Apache License, Version 2.0
- MIT License
at your option.
Version
Current version: 1.2.0
Compatible with:
- Leptos 0.8.15
- Rust 1.75+
- UnoCSS 0.63+
Changelog:
- 1.2.0 (2026-02-08): Core components complete (Button, Input, Table, Modal, Pagination, FormField, Toast, Card, Badge, Spinner, SpaLink, Portal)
- 1.0.0 (2026-01-11): Initial release