A comprehensive Rust component library bringing Bulma CSS components to Dioxus applications.
Build beautiful, responsive web applications with the power of Rust and the elegance of Bulma CSS.
- π¨ Complete Bulma Integration: All Bulma CSS components implemented as Dioxus components
- β‘ Type-Safe: Leverages Rust's type system for compile-time guarantees and better developer experience
- π― Dioxus Native: Built specifically for the Dioxus ecosystem with proper event handling
- π± Responsive Design: Mobile-first responsive design patterns out of the box
- π Theme Support: Light/dark/auto theme modes with CSS custom properties
- π§© Composable Architecture: Mix and match components with consistent APIs
- ποΈ Rich Props System: Extensive customization through typed props
- π¦ Zero Runtime Dependencies: Pure Rust implementation
Add this to your Cargo.toml:
[dependencies]
dioxus-bulma = "0.7"
dioxus = "0.7"For web applications, enable the web feature:
[features]
default = []
web = ["dioxus/web"]
router = ["dioxus-bulma/router"] # Optional: Enable router integrationEnable router support for seamless navigation with dioxus-router:
[dependencies]
dioxus-bulma = { version = "0.7", features = ["router"] }
dioxus-router = "0.7"When the router feature is enabled, components like Button, MenuItem,
BreadcrumbItem, DropdownItem, PanelBlock, PaginationLink,
PaginationPrevious, PaginationNext and Tab accept a to prop that takes
any Routable route (or anything else that implements
Into<NavigationTarget>) directly:
MenuItem { to: Route::DeviceList, "Devices" } // β
works
BreadcrumbItem { to: Route::Home, "Home" } // β
worksThis is enabled by the MaybeNav
wrapper plus #[props(into)].
Every component exposes an id: Option<String> prop that is forwarded to the
rendered root element. This makes it easy for tooling, end-to-end test
frameworks (Playwright, Cypress) and CSS to target individual components:
Button { id: "save-button", color: BulmaColor::Primary, "Save" }
Notification { id: "save-success", color: BulmaColor::Success, "Saved!" }This library is fully compatible with Dioxus 0.7. If you're upgrading from Dioxus 0.6, see the Upgrade Guide section below.
Start by wrapping your app with BulmaProvider to enable theme support and CSS loading:
use dioxus::prelude::*;
use dioxus_bulma::prelude::*;
use dioxus_bulma::components::{Title, Subtitle};
fn main() {
launch(App);
}
#[component]
fn App() -> Element {
rsx! {
BulmaProvider {
theme: BulmaTheme::Auto, // Auto-detect system theme
load_bulma_css: true, // Auto-load Bulma CSS from CDN
Section {
Container {
Title { size: TitleSize::Is1, "Hello, Dioxus Bulma!" }
Subtitle { "Build beautiful web apps with Rust" }
Button {
color: BulmaColor::Primary,
size: BulmaSize::Large,
"Get Started"
}
}
}
}
}
}The library provides two import patterns:
Recommended: Using the prelude
use dioxus::prelude::*;
use dioxus_bulma::prelude::*;
// Bulma's typography components are exposed as `BulmaTitle`/`BulmaSubtitle` via
// the prelude to avoid colliding with Dioxus 0.7's built-in document `Title`.Alternative: Component module (use the original Bulma names)
use dioxus::prelude::*;
use dioxus_bulma::prelude::*;
use dioxus_bulma::components::{Title, Subtitle};Note: Dioxus 0.7's
dioxus::preludealready contains aTitledocument component that mutates the page<title>. Bulma's typography components are therefore re-exported under the namesBulmaTitleandBulmaSubtitlefrom the prelude. The originalTitle/Subtitlenames are still available viadioxus_bulma::components.
Create interactive forms with validation:
#[component]
fn ContactForm() -> Element {
let mut name = use_signal(String::new);
let mut email = use_signal(String::new);
rsx! {
Card {
CardHeader { CardHeaderTitle { "Contact Us" } }
CardContent {
Field {
Label { "Name" }
Control {
Input {
input_type: InputType::Text,
placeholder: "Enter your name",
value: name(),
oninput: move |evt: FormEvent| name.set(evt.value())
}
}
}
Field {
Label { "Email" }
Control {
Input {
input_type: InputType::Email,
placeholder: "Enter your email",
color: if email().contains('@') {
Some(BulmaColor::Success)
} else {
None
},
value: email(),
oninput: move |evt: FormEvent| email.set(evt.value())
}
}
Help { color: BulmaColor::Info, "We'll never share your email" }
}
Field { grouped: true,
Control {
Button {
color: BulmaColor::Primary,
onclick: move |_| {
println!("Submitted: {} - {}", name(), email());
},
"Submit"
}
}
Control {
Button {
onclick: move |_| {
name.set(String::new());
email.set(String::new());
},
"Clear"
}
}
}
}
}
}
}Use Bulma's flexible grid system:
#[component]
fn GridLayout() -> Element {
rsx! {
Container {
Columns {
multiline: true,
Column { size: ColumnSize::Half,
Card {
CardContent {
Title { size: TitleSize::Is4, "Half Width" }
Content { "This column takes half the available width." }
}
}
}
Column { size: ColumnSize::OneQuarter,
Card {
CardContent {
Title { size: TitleSize::Is4, "Quarter Width" }
Content { "This column takes one quarter of the width." }
}
}
}
Column { size: ColumnSize::OneQuarter,
Card {
CardContent {
Title { size: TitleSize::Is4, "Quarter Width" }
Content { "Another quarter width column." }
}
}
}
}
}
}
}Use components with dioxus-router for client-side navigation:
use dioxus::prelude::*;
use dioxus_bulma::*;
#[derive(Clone, Routable, Debug, PartialEq)]
enum Route {
#[route("/")]
Home {},
#[route("/about")]
About {},
#[route("/contact")]
Contact {},
}
#[component]
fn App() -> Element {
rsx! {
BulmaProvider {
theme: BulmaTheme::Auto,
load_bulma_css: true,
Router::<Route> {}
// Navigation with router-enabled components
Section {
Container {
// Button navigation
Field { grouped: true,
Control {
Button {
color: BulmaColor::Primary,
to: Route::Home {},
"Home"
}
}
Control {
Button {
color: BulmaColor::Link,
to: Route::About {},
"About"
}
}
Control {
Button {
color: BulmaColor::Info,
to: Route::Contact {},
"Contact"
}
}
}
// Breadcrumb navigation
Breadcrumb {
BreadcrumbItem { to: Route::Home {}, "Home" }
BreadcrumbItem { to: Route::About {}, "About" }
BreadcrumbItem { active: true, "Current Page" }
}
// Content
Outlet::<Route> {}
}
}
}
}
}
#[component]
fn Home() -> Element {
rsx! {
Title { size: TitleSize::Is2, "Welcome Home" }
Content { "This is the home page." }
}
}
#[component]
fn About() -> Element {
rsx! {
Title { size: TitleSize::Is2, "About Us" }
Content { "Learn more about our company." }
}
}
#[component]
fn Contact() -> Element {
rsx! {
Title { size: TitleSize::Is2, "Contact" }
Content { "Get in touch with us." }
}
}Leverage advanced components like dropdowns and modals:
#[component]
fn AdvancedDemo() -> Element {
let mut show_modal = use_signal(|| false);
let mut dropdown_active = use_signal(|| false);
rsx! {
// Dropdown
Dropdown {
active: dropdown_active(),
DropdownTrigger {
onclick: move |_| dropdown_active.set(!dropdown_active()),
Button { color: BulmaColor::Primary, "Options βΌ" }
}
DropdownMenu {
DropdownItem { "Action" }
DropdownItem { "Another action" }
DropdownDivider {}
DropdownItem { active: true, "Active item" }
}
}
// Modal trigger
Button {
color: BulmaColor::Info,
onclick: move |_| show_modal.set(true),
"Open Modal"
}
// Modal
Modal {
active: show_modal(),
onclose: move |_| show_modal.set(false),
ModalCard {
ModalCardHead {
onclose: move |_| show_modal.set(false),
Title { size: TitleSize::Is4, "Modal Title" }
}
ModalCardBody {
Content { "This is the modal content!" }
}
ModalCardFoot {
Button {
color: BulmaColor::Success,
onclick: move |_| show_modal.set(false),
"Save"
}
Button {
onclick: move |_| show_modal.set(false),
"Cancel"
}
}
}
}
}
}Container- Responsive container with breakpoint optionsSection- Page sections with size variantsColumns/Column- Flexible grid system with responsive sizing and offsetsHero/HeroBody/HeroHead/HeroFoot- Hero banner components with sizesLevel/LevelLeft/LevelRight/LevelItem- Horizontal level layoutMedia/MediaLeft/MediaContent/MediaRight- Media object layoutTile- Metro-style tile layout system
Button- Full-featured buttons with colors, sizes, states, and variantsBulmaBox(also exported asBoxfromdioxus_bulma::components) - The Bulmaboxelement, a simple bordered containerBlock- Bulmablockspacer for consistent vertical rhythmTitle/Subtitle- Typography components with proper heading levels (re-exported asBulmaTitle/BulmaSubtitlefrom the prelude)Content- Rich content container with typography stylesDelete- Delete button with size variantsIcon- Icon wrapper with size and color optionsImage- Image container with responsive sizing optionsNotification- Dismissible alert notifications with colors and light variantsProgress- Progress bars with colors and valuesTable- Data tables with styling options (bordered, striped, hoverable)Tag/Tags- Label and tag components with colors, sizes, and variants
Input- Text inputs with validation states, icons, and various typesTextarea- Multi-line text areas with rows and validationSelect- Dropdown select inputs with multiple optionsCheckbox- Checkbox inputs with labelsRadio- Radio button inputs with groupingFile- File input components with custom stylingField- Form field wrapper with grouping and addon optionsControl- Form control wrapper with icon and loading supportLabel- Form labels with proper associationHelp- Form help text with color states
Breadcrumb/BreadcrumbItem- Breadcrumb navigation with separatorsTabs/Tab- Tab navigation with styles (default, boxed, toggle)Pagination/PaginationPrevious/PaginationNext/PaginationList/PaginationLink/PaginationEllipsis- Pagination controls
Card/CardHeader/CardHeaderTitle/CardContent/CardFooter/CardFooterItem- Card componentsDropdown/DropdownTrigger/DropdownMenu/DropdownItem/DropdownDivider- Dropdown menusMenu/MenuLabel/MenuList/MenuItem- Vertical navigation menusMessage/MessageHeader/MessageBody- Message components with colors and close functionalityModal/ModalCard/ModalCardHead/ModalCardBody/ModalCardFoot- Modal dialogsNavbar/NavbarBrand/NavbarMenu/NavbarItem- Navigation barsPanel/PanelHeading/PanelTabs/PanelBlock/PanelIcon- Panel components
When the router feature is enabled, these components support the to prop for client-side navigation:
Button- Navigate on click instead of form submissionBreadcrumbItem- Router-aware breadcrumb navigationDropdownItem- Navigate from dropdown menusMenuItem- Navigate from vertical menusPanelBlock- Navigate from panel itemsPaginationPrevious/PaginationNext/PaginationLink- Navigate between pages
Router Props:
to: Route- Navigate to route (takes priority overhref)href: String- Fallback for regular link behavior- All existing styling and event props work normally
Run the examples to see all components in action:
# Basic demo with core components
cargo run --example demo --features web
# Interactive showcase with all components
cargo run --example showcase --features web
# Comprehensive demo showcasing all features
cargo run --example comprehensive_demo --features webEach example demonstrates different aspects:
- demo: Basic usage patterns and core components
- showcase: Interactive components with state management
- comprehensive_demo: Complete feature set including forms, navigation, and advanced components
All components support Bulma's color system:
BulmaColor::Primary | Link | Info | Success | Warning | Danger |
White | Light | Dark | Black | Text | GhostSize variants available:
BulmaSize::Small | Normal | Medium | LargeButton {
color: BulmaColor::Primary, // Color scheme
size: BulmaSize::Medium, // Button size
outlined: true, // Outlined style
rounded: true, // Rounded corners
loading: false, // Loading state
disabled: false, // Disabled state
fullwidth: false, // Full width
onclick: |_| { /* handler */ }, // Click handler
"Button Text"
}Input {
input_type: InputType::Email, // Text, Email, Password, etc.
placeholder: "Enter email...", // Placeholder text
value: email_value, // Controlled value
color: BulmaColor::Success, // Validation color
size: BulmaSize::Large, // Input size
readonly: false, // Read-only state
disabled: false, // Disabled state
oninput: |evt| { /* handler */ } // Input handler
}Card {
CardHeader {
CardHeaderTitle { "Card Title" }
}
CardContent {
// Main content
}
CardFooter {
CardFooterItem { href: "#", "Action" }
CardFooterItem { "Another Action" }
}
}Columns {
multiline: true, // Allow wrapping
centered: false, // Center columns
vcentered: false, // Vertical centering
mobile: false, // Force on mobile
Column {
size: ColumnSize::Half, // Fractional sizing
offset: ColumnSize::OneQuarter, // Column offset
// Content
}
}Wrap your app with BulmaProvider to enable theming:
BulmaProvider {
theme: BulmaTheme::Auto, // Auto, Light, or Dark
load_bulma_css: true, // Auto-load Bulma CSS from CDN
// Your app components...
}This library provides a complete implementation of Bulma CSS components for Dioxus applications.
- Layout Components: Container, Columns/Column, Section, Hero, Level, Media, Tile
- Elements: Button, Title/Subtitle, Content, Delete, Icon, Image, Notification, Progress, Table, Tag/Tags
- Form Components: Input, Textarea, Select, Checkbox, Radio, File, Field, Control, Label, Help
- Navigation: Breadcrumb, Tabs, Pagination with all sub-components
- Advanced Components: Card, Dropdown, Menu, Message, Modal, Navbar, Panel
- Theme System: Complete BulmaProvider with light/dark/auto themes
- Type-safe props with comprehensive validation
- Consistent event handling across all components
- Responsive design patterns built-in
- Full Bulma CSS class coverage
- Zero runtime dependencies
- Comprehensive examples and documentation
All core Bulma components are implemented and thoroughly tested. The library is suitable for production use in Dioxus web applications.
// Prefer semantic composition
Card {
CardHeader { CardHeaderTitle { "User Profile" } }
CardContent {
Media {
MediaLeft { Image { /* avatar */ } }
MediaContent { /* user info */ }
}
}
CardFooter {
CardFooterItem { "Edit" }
CardFooterItem { "Delete" }
}
}
// Over flat structures
div { class: "card",
div { class: "card-header", /* ... */ }
div { class: "card-content", /* ... */ }
}// Use color props for visual validation feedback
Input {
color: if is_valid { BulmaColor::Success } else { BulmaColor::Danger },
// ...
}
Help {
color: BulmaColor::Danger,
"Please enter a valid email address"
}// Leverage Bulma's responsive system
Columns {
Column { size: ColumnSize::IsFullMobile, /* mobile: full width */ }
Column { size: ColumnSize::IsHalfTablet, /* tablet: half width */ }
}Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
git clone https://github.com/your-username/dioxus-bulma
cd dioxus-bulma
cargo check
cargo run --example comprehensive_demo --features webIf you're upgrading from Dioxus 0.6, follow these steps to update your dioxus-bulma integration:
[dependencies]
dioxus = "0.7"
dioxus-bulma = "0.7"
dioxus-router = "0.7" # if using routerBefore (Dioxus 0.6):
use dioxus::prelude::*;
use dioxus_bulma::*;After (Dioxus 0.7):
use dioxus::prelude::*;
use dioxus_bulma::prelude::*;
use dioxus_bulma::components::{Title, Subtitle}; // Explicit imports to avoid conflictsDioxus 0.7 renamed use_state to use_signal:
Before:
let mut count = use_state(|| 0);After:
let mut count = use_signal(|| 0);In Dioxus 0.7, the children prop in component props is required (no longer optional):
Before:
#[derive(Props, Clone, PartialEq)]
pub struct MyComponentProps {
#[props(default)]
pub children: Option<Element>,
}After:
#[derive(Props, Clone, PartialEq)]
pub struct MyComponentProps {
pub children: Element, // Required, no default
}Dioxus 0.7 introduces built-in document components (Title, Subtitle) that may conflict with dioxus-bulma components. Always import them explicitly from the components module to ensure you're using the Bulma versions.
For more detailed information, refer to the Dioxus 0.7 Release Notes.
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.