Containers & Overlays
Components for organizing content, managing layers, and showing floating UI.
Modal
Controlled dialog overlay with backdrop, escape-to-dismiss, and click-outside handling:
#![allow(unused)]
fn main() {
use kael::modal;
modal("confirm-dialog", self.is_open)
.label("Confirm action")
.backdrop(hsla(0.0, 0.0, 0.0, 0.5))
.dismiss_on_escape(true)
.dismiss_on_click_outside(true)
.render_with({
let entity = entity.clone();
move |state, _window, _cx| {
div()
.w(px(400.0))
.p_6()
.bg(rgb(0xffffff))
.rounded(px(12.0))
.shadow_xl()
.flex().flex_col().gap_4()
.child(div().text_lg().child("Are you sure?"))
.child(div().child("This action cannot be undone."))
.child(
div().flex().justify_end().gap_2()
.child(button("cancel").label("Cancel")
.on_click({
let entity = entity.clone();
move |_, _, cx| {
entity.update(cx, |this, cx| {
this.is_open = false;
cx.notify();
});
}
}))
.child(button("confirm").label("Confirm")
.on_click({
let entity = entity.clone();
move |_, _, cx| {
entity.update(cx, |this, cx| {
this.do_action();
this.is_open = false;
cx.notify();
});
}
}))
)
.into_any_element()
}
})
.on_change({
let entity = entity.clone();
move |open, _window, cx| {
entity.update(cx, |this, cx| {
this.is_open = *open;
cx.notify();
});
}
})
}
ModalRenderState fields: open, label, focused
Popover
Anchored floating panel with positioning:
#![allow(unused)]
fn main() {
use kael::popover;
popover("color-picker")
.anchor(|_window, _cx| {
button("show-colors").label("Colors").into_any_element()
})
.popup(|_window, _cx| {
div()
.w(px(200.0))
.p_3()
.bg(rgb(0xffffff))
.shadow_lg()
.rounded(px(8.0))
.child("Color picker content")
.into_any_element()
})
.dismiss_on_escape(true)
.dismiss_on_click_outside(true)
}
Tabs
Tabbed content switcher with keyboard navigation:
#![allow(unused)]
fn main() {
use kael::tabs;
#[derive(Clone, Copy, PartialEq, Eq)]
enum EditorTab { Code, Preview, Settings }
tabs("editor-tabs", self.active_tab, [
TabItem::new(EditorTab::Code, "Code", |_w, _cx| {
div().child("Code editor here").into_any_element()
}),
TabItem::new(EditorTab::Preview, "Preview", |_w, _cx| {
div().child("Live preview").into_any_element()
}),
TabItem::new(EditorTab::Settings, "Settings", |_w, _cx| {
div().child("Editor settings").into_any_element()
}),
])
.on_change({
let entity = entity.clone();
move |tab, _window, cx| {
entity.update(cx, |this, cx| {
this.active_tab = *tab;
cx.notify();
});
}
})
}
TabRenderState fields: value, label, index, tab_count, selected, focused
Disclosure
Collapsible section (accordion):
#![allow(unused)]
fn main() {
use kael::disclosure;
disclosure("advanced-settings", self.expanded)
.trigger(|_w, _cx| {
div().child("Advanced Settings ▾").into_any_element()
})
.panel(|_w, _cx| {
div().p_3().child("Hidden content here").into_any_element()
})
.on_change({
let entity = entity.clone();
move |open, _window, cx| {
entity.update(cx, |this, cx| {
this.expanded = *open;
cx.notify();
});
}
})
}
Splitter
Draggable pane divider for resizable layouts:
#![allow(unused)]
fn main() {
use kael::splitter;
splitter("main-split", self.split_ratio)
.on_change({
let entity = entity.clone();
move |ratio, _window, cx| {
entity.update(cx, |this, cx| {
this.split_ratio = *ratio;
cx.notify();
});
}
})
}
Use the ratio value to size adjacent panes:
#![allow(unused)]
fn main() {
let left_width = self.split_ratio * total_width;
div().flex().flex_row()
.child(div().w(px(left_width)).child("Left pane"))
.child(splitter("split", self.split_ratio).on_change(/* ... */))
.child(div().flex_1().child("Right pane"))
}
Context Menu
Right-click menus via .context_menu() on any Div:
#![allow(unused)]
fn main() {
div()
.id("file-item")
.child("document.txt")
.context_menu(|menu| {
menu.item("Open", |_w, cx| { /* handle open */ })
.item("Rename", |_w, cx| { /* handle rename */ })
.separator()
.item("Delete", |_w, cx| { /* handle delete */ })
})
}
Tooltip
Hover information via .tooltip() on any Div:
#![allow(unused)]
fn main() {
div()
.id("save-icon")
.child(icon("save"))
.tooltip("Save file (Cmd+S)")
// Custom tooltip content
div()
.id("status")
.child("●")
.tooltip_element(|| {
div()
.p_2()
.bg(rgb(0x1E1E1E))
.text_color(rgb(0xffffff))
.rounded(px(4.0))
.child("Connected to server")
})
}
Layer
Managed layer system for in-window modals and popovers:
#![allow(unused)]
fn main() {
use kael::layer;
layer("notification-layer")
.placement(LayerPlacement::Centered)
.child(/* floating content */)
}