Widgets
Makara provides a comprehensive set of built-in widgets for building modern GUI applications. Each widget comes with styling options, event handling capabilities, and built-in class support for rapid development.
Container Widgets
Container widgets manage layout and can contain child elements.
Root
The root_! widget is the starting point for your UI hierarchy and must be spawned by commands. It supports alignment utility classes.
Basic Usage:
#![allow(unused)]
fn main() {
commands.spawn(root_!([
text_!("Hello World")
]));
}
With styling and alignment:
#![allow(unused)]
fn main() {
commands.spawn(
root_!(
background_color: Color::srgb(0.1, 0.1, 0.2),
class: "justify-center align-center p-4",
[
column_!([
text_!("Welcome to Makara!"),
button_!("Get Started")
])
]
)
);
}
With custom properties:
#![allow(unused)]
fn main() {
commands.spawn(
root_!(
width: percent(100),
height: percent(100),
id: "main-container",
class: "justify-between align-stretch",
[/* children */]
)
);
}
Column
The column_! widget arranges children vertically in a flexbox column layout.
Basic Usage:
#![allow(unused)]
fn main() {
column_!([
text_!("Item 1"),
text_!("Item 2"),
text_!("Item 3")
])
}
With alignment and spacing:
#![allow(unused)]
fn main() {
column_!(
class: "justify-center align-center p-4 m-2",
background_color: "white",
[
text_!("Centered Column", font_size: 24.0),
button_!("Action Button", class: "is-primary mt-3"),
text_!("Footer text", class: "mt-2")
]
)
}
With event handling:
#![allow(unused)]
fn main() {
column_!(
on: |_built: On<WidgetBuilt>| {
println!("Column widget built!");
},
[/* children */]
)
}
Row
The row_! widget arranges children horizontally in a flexbox row layout.
Basic Usage:
#![allow(unused)]
fn main() {
row_!([
text_!("Left"),
text_!("Center"),
text_!("Right")
])
}
Navigation bar example:
#![allow(unused)]
fn main() {
row_!(
class: "justify-between align-center p-3",
background_color: Color::srgb(0.2, 0.3, 0.8),
[
text_!("MyApp", font_size: 20.0, color: Color::WHITE),
row_!(
class: "justify-end align-center",
[
button_!("Home", class: "mr-2"),
button_!("About", class: "mr-2"),
button_!("Contact")
]
)
]
)
}
Scroll
The scroll_! widget creates a scrollable container for content that exceeds the container size.
Basic Usage:
#![allow(unused)]
fn main() {
scroll_!([
text_!("Line 1"),
text_!("Line 2"),
text_!("Line 3"),
// ... many more lines
])
}
Styled scroll container:
#![allow(unused)]
fn main() {
scroll_!(
width: px(300),
height: px(200),
class: "p-3",
background_color: Color::srgb(0.95, 0.95, 0.95),
[
column_!(
class: "justify-start align-stretch",
[
text_!("Scrollable Content", font_size: 18.0, class: "mb-2"),
text_!("This is line 1"),
text_!("This is line 2"),
// ... more content
]
)
]
)
}
With scroll event handling:
#![allow(unused)]
fn main() {
scroll_!(
on: |scrolling: On<Scrolling>| {
println!("User is scrolling!");
},
[/* scrollable content */]
)
}
Interactive Widgets
Button
The button_! widget provides clickable interactions with built-in hover states.
Basic Usage:
#![allow(unused)]
fn main() {
button_!("Click Me")
}
With styling:
#![allow(unused)]
fn main() {
button_!("Submit", class: "is-primary p-3 m-2")
}
With event handling:
#![allow(unused)]
fn main() {
button_!(
"Save Data";
on: |clicked: On<Clicked>| {
println!("Save button clicked!");
},
on: |over: On<MouseOver>| {
println!("Mouse over save button");
},
on: |out: On<MouseOut>| {
println!("Mouse left save button");
}
)
}
Complete example with styling and events:
#![allow(unused)]
fn main() {
button_!(
"Delete Item",
id: "delete-btn",
class: "is-danger p-2 m-1",
on: |clicked: On<Clicked>| {
// Handle delete action
},
on: |built: On<WidgetBuilt>| {
println!("Delete button ready!");
}
)
}
Text Input
The text_input_! widget provides text entry with placeholder support and theming.
Basic Usage:
#![allow(unused)]
fn main() {
text_input_!("Enter your name...")
}
With styling and validation:
#![allow(unused)]
fn main() {
text_input_!(
"Enter email address...",
class: "is-primary p-2",
width: px(300),
id: "email-input"
)
}
With change event handling:
#![allow(unused)]
fn main() {
text_input_!(
"Search...";
on: |change: On<Change<String>>| {
println!("Search text: {}", change.data);
};
on: |clicked: On<Clicked>| {
println!("Input field focused");
}
)
}
Form example:
#![allow(unused)]
fn main() {
column_!(
class: "justify-start align-stretch p-4";
[
text_!("User Registration", font_size: 20.0, class: "mb-3"),
text_input_!("Full Name...", class: "mb-2", width: px(300)),
text_input_!("Email Address...", class: "is-info mb-2", width: px(300)),
text_input_!("Password...", class: "is-warning mb-3", width: px(300)),
button_!("Register", class: "is-success")
]
)
}
Checkbox
The checkbox_! widget provides boolean toggle functionality.
Basic Usage:
#![allow(unused)]
fn main() {
checkbox_!("Accept terms and conditions")
}
With styling:
#![allow(unused)]
fn main() {
checkbox_!("Enable notifications", class: "is-primary p-2")
}
With state change handling:
#![allow(unused)]
fn main() {
checkbox_!(
"Subscribe to newsletter";
on: |active: On<Active<String>>| {
println!("Checkbox activated: {}", active.data);
};
on: |inactive: On<Inactive<String>>| {
println!("Checkbox deactivated: {}", inactive.data);
}
)
}
Settings panel example:
#![allow(unused)]
fn main() {
column_!(
class: "justify-start align-start p-4";
[
text_!("Settings", font_size: 18.0, class: "mb-3"),
checkbox_!("Dark mode", class: "is-info mb-2"),
checkbox_!("Auto-save", class: "is-success mb-2"),
checkbox_!("Show tooltips", class: "is-primary mb-2"),
button_!("Apply Settings", class: "is-primary mt-2")
]
)
}
Radio Group & Radio
Radio widgets provide single-selection from multiple options.
Basic Usage:
#![allow(unused)]
fn main() {
radio_group_!([
radio_!("Option A"),
radio_!("Option B"),
radio_!("Option C")
])
}
Payment method selector:
#![allow(unused)]
fn main() {
radio_group_!(
class: "p-3";
on: |change: On<Change<String>>| {
println!("Selected payment method: {}", change.data);
};
[
radio_!("Credit Card", class: "is-primary mb-2"),
radio_!("PayPal", class: "is-info mb-2"),
radio_!("Bank Transfer", class: "is-success mb-2"),
radio_!("Cash on Delivery", class: "is-warning")
]
)
}
With individual radio event handling:
#![allow(unused)]
fn main() {
radio_group_!([
radio_!(
"Small Size";
on: |active: On<Active>| {
println!("Small size selected");
}
),
radio_!("Medium Size"),
radio_!("Large Size")
])
}
Select
The select_! widget provides a dropdown selection interface.
Basic Usage:
#![allow(unused)]
fn main() {
select_!("Choose country...", choices: &["USA", "Canada", "Mexico"])
}
With styling and events:
#![allow(unused)]
fn main() {
select_!(
"Select payment method...",
choices: &["Credit Card", "Debit Card", "PayPal"],
class: "is-primary p-2",
width: px(250);
on: |change: On<Change<String>>| {
println!("Selected: {}", change.data);
};
on: |active: On<Active>| {
println!("Dropdown opened");
};
on: |inactive: On<Inactive>| {
println!("Dropdown closed");
}
)
}
Form integration:
#![allow(unused)]
fn main() {
column_!(
class: "justify-start align-stretch p-4";
[
text_!("Shipping Information"),
select_!("Country...", choices: &["USA", "Canada", "UK"], class: "mb-2"),
select_!("State/Province...", choices: &["CA", "NY", "TX"], class: "mb-2"),
button_!("Continue", class: "is-success")
]
)
}
Dropdown
The dropdown_! widget creates a button that shows/hides child content.
Basic Usage:
#![allow(unused)]
fn main() {
dropdown_!(
"Menu";
[
button_!("Profile"),
button_!("Settings"),
button_!("Logout")
]
)
}
Navigation dropdown:
#![allow(unused)]
fn main() {
dropdown_!(
"Products",
class: "is-primary";
on: |clicked: On<Clicked>| {
println!("Products dropdown toggled");
};
[
button_!("Laptops", class: "mb-1"),
button_!("Phones", class: "mb-1"),
button_!("Tablets", class: "mb-1"),
button_!("Accessories")
]
)
}
Slider
The slider_! widget provides numeric input via draggable control.
Basic Usage:
#![allow(unused)]
fn main() {
slider_!(min: 0.0, max: 100.0)
}
Volume control example:
#![allow(unused)]
fn main() {
column_!(
class: "justify-start align-center p-4";
[
text_!("Volume Control", class: "mb-2"),
slider_!(
min: 0.0,
max: 100.0,
class: "is-primary p-2";
on: |change: On<Change<f32>>| {
println!("Volume: {:.1}%", change.data);
}
)
]
)
}
Settings panel with multiple sliders:
#![allow(unused)]
fn main() {
column_!(
class: "justify-start align-stretch p-4";
[
text_!("Audio Settings", font_size: 18.0, class: "mb-3"),
column_!(class: "mb-2"; [
text_!("Master Volume"),
slider_!(min: 0.0, max: 100.0, class: "is-primary")
]),
column_!(class: "mb-2"; [
text_!("Music Volume"),
slider_!(min: 0.0, max: 100.0, class: "is-info")
]),
column_!(class: "mb-2"; [
text_!("Effects Volume"),
slider_!(min: 0.0, max: 100.0, class: "is-success")
])
]
)
}
Display Widgets
Text
The text_! widget displays styled text content.
Basic Usage:
#![allow(unused)]
fn main() {
text_!("Hello World")
}
With styling:
#![allow(unused)]
fn main() {
text_!("Welcome!", font_size: 24.0, color: Color::srgb(0.2, 0.6, 0.8))
}
With classes:
#![allow(unused)]
fn main() {
text_!("Error message", class: "is-danger", font_size: 16.0)
}
Typography example:
#![allow(unused)]
fn main() {
column_!(
class: "justify-start align-start p-4";
[
text_!("Main Heading", font_size: 32.0, class: "mb-3"),
text_!("Subheading", font_size: 20.0, class: "is-info mb-2"),
text_!("Regular paragraph text with some content.", font_size: 14.0, class: "mb-2"),
text_!("Small caption text", font_size: 12.0, class: "is-secondary")
]
)
}
Image
The image_! widget displays images from file paths or URLs.
Basic Usage:
#![allow(unused)]
fn main() {
image_!("assets/logo.png")
}
With sizing:
#![allow(unused)]
fn main() {
image_!(
"assets/hero-banner.jpg",
width: px(400),
height: px(200)
)
}
With events:
#![allow(unused)]
fn main() {
image_!(
"assets/profile.png";
on: |clicked: On<Clicked>| {
println!("Profile image clicked");
};
on: |over: On<MouseOver>| {
println!("Hovering over image");
}
)
}
Image gallery example:
#![allow(unused)]
fn main() {
row_!(
class: "justify-around align-center p-4";
[
image_!("assets/thumb1.jpg", width: px(150), height: px(150)),
image_!("assets/thumb2.jpg", width: px(150), height: px(150)),
image_!("assets/thumb3.jpg", width: px(150), height: px(150))
]
)
}
Link
The link_! widget creates clickable links that open in the browser.
Basic Usage:
#![allow(unused)]
fn main() {
link_!("https://rust-lang.org/")
}
With custom text:
#![allow(unused)]
fn main() {
link_!("Visit Rust Website", url: "https://rust-lang.org/")
}
With styling and events:
#![allow(unused)]
fn main() {
link_!(
"Documentation",
url: "https://docs.rs/makara",
class: "is-primary";
on: |clicked: On<Clicked>| {
println!("Documentation link clicked");
}
)
}
Footer links example:
#![allow(unused)]
fn main() {
row_!(
class: "justify-center align-center p-3";
[
link_!("Privacy Policy", url: "https://example.com/privacy", class: "mr-4"),
link_!("Terms of Service", url: "https://example.com/terms", class: "mr-4"),
link_!("Contact Us", url: "https://example.com/contact")
]
)
}
Progress & Loading Widgets
Progress Bar
The progress_bar_! widget shows linear progress indication.
Basic Usage:
#![allow(unused)]
fn main() {
progress_bar_!()
}
With styling:
#![allow(unused)]
fn main() {
progress_bar_!(
class: "is-primary p-2",
width: px(300)
)
}
With progress tracking:
#![allow(unused)]
fn main() {
progress_bar_!(
class: "is-success";
on: |change: On<Change<f32>>| {
println!("Progress: {:.1}%", change.data * 100.0);
}
)
}
Loading interface example:
#![allow(unused)]
fn main() {
column_!(
class: "justify-center align-center p-4";
[
text_!("Loading...", class: "mb-2"),
progress_bar_!(class: "is-info", width: px(250)),
text_!("Please wait while we process your request",
font_size: 12.0, class: "mt-2")
]
)
}
Circular
The circular_! widget shows circular/spinner progress indication.
Basic Usage:
#![allow(unused)]
fn main() {
circular_!()
}
With styling:
#![allow(unused)]
fn main() {
circular_!(
class: "is-primary p-3",
width: px(50),
height: px(50)
)
}
Loading spinner example:
#![allow(unused)]
fn main() {
column_!(
class: "justify-center align-center p-4";
[
circular_!(class: "is-info mb-3"),
text_!("Processing...", class: "is-info")
]
)
}
Modal
The modal_! widget creates overlay dialogs and is independent of the root widget hierarchy.
Basic Usage:
#![allow(unused)]
fn main() {
commands.spawn(
modal_!([
column_!([
text_!("Are you sure?"),
button_!("Confirm")
])
])
);
}
Confirmation dialog:
#![allow(unused)]
fn main() {
modal_!(
on: |active: On<Active>| {
println!("Modal opened");
};
on: |inactive: On<Inactive>| {
println!("Modal closed");
};
[
column_!(
class: "justify-center align-center p-4",
background_color: Color::WHITE,
width: px(300),
height: px(200);
[
text_!("Delete Confirmation", font_size: 18.0, class: "mb-3"),
text_!("Are you sure you want to delete this item?", class: "mb-4"),
row_!(
class: "justify-center align-center";
[
button_!("Cancel", class: "is-secondary mr-2"),
button_!("Delete", class: "is-danger")
]
)
]
)
]
)
}
Settings modal:
#![allow(unused)]
fn main() {
modal_!([
column_!(
class: "justify-start align-stretch p-4",
background_color: Color::WHITE,
width: px(400),
height: px(500);
[
text_!("Settings", font_size: 24.0, class: "mb-4"),
checkbox_!("Enable notifications", class: "mb-2"),
checkbox_!("Auto-save documents", class: "mb-2"),
text_!("Theme", class: "mb-1"),
select_!("Choose theme...", choices: &["Light", "Dark", "Auto"], class: "mb-4"),
row_!(
class: "justify-end align-center";
[
button_!("Cancel", class: "mr-2"),
button_!("Save", class: "is-primary")
]
)
]
)
])
}
Built-in Classes
All widgets support built-in utility classes:
Color Classes
is-primary,is-primary-darkis-link,is-link-darkis-info,is-info-darkis-success,is-success-darkis-warning,is-warning-darkis-danger,is-danger-dark
Spacing Classes (Container widgets only)
- Margin:
m-0tom-6,mt-2,mr-3,mb-1,ml-4,mx-2,my-3 - Padding:
p-0top-6,pt-2,pr-3,pb-1,pl-4,px-2,py-3
Alignment Classes (Container widgets only)
- Justify:
justify-start,justify-center,justify-end,justify-between,justify-around,justify-evenly - Align:
align-start,align-center,align-end,align-stretch,align-baseline
Complete Example
Here’s a complete application example using multiple widgets:
#![allow(unused)]
fn main() {
use makara::prelude::*;
use bevy::prelude::*;
fn setup(mut commands: Commands) {
commands.spawn(
root_!(
class: "justify-center align-center p-4",
background_color: Color::srgb(0.9, 0.9, 0.9);
[
column_!(
class: "justify-start align-stretch p-4",
background_color: Color::WHITE,
width: px(500);
[
// Header
text_!("User Profile", font_size: 24.0, class: "mb-4"),
// Profile image
row_!(
class: "justify-center align-center mb-4";
[
image_!("assets/avatar.png", width: px(100), height: px(100))
]
),
// Form fields
text_input_!("Full Name...", class: "mb-2"),
text_input_!("Email...", class: "is-info mb-2"),
// Preferences
text_!("Preferences", font_size: 16.0, class: "mb-2"),
checkbox_!("Email notifications", class: "mb-1"),
checkbox_!("Dark mode", class: "mb-3"),
// Theme selection
select_!("Theme...", choices: &["Light", "Dark", "Auto"], class: "mb-4"),
// Actions
row_!(
class: "justify-end align-center";
[
button_!("Cancel", class: "mr-2"),
button_!("Save Profile", class: "is-primary")
]
)
]
)
]
)
);
}
}
For detailed API documentation, visit the Rust docs.