Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Augani/kael/llms.txt

Use this file to discover all available pages before exploring further.

Kael ships a rich standard library of UI primitives that cover the vast majority of what native desktop applications need. Every element is GPU-accelerated, composable, and styled through the same Tailwind-inspired API. Whether you are building a simple form or a data-dense dashboard, these building blocks form the foundation of every Kael render tree.

Container: div()

div() is the core layout container in Kael — the equivalent of the HTML <div>. It accepts children, handles all layout and style methods, and is the primary surface for binding mouse events, focus, tooltips, and context menus. Most custom components are assembled from one or more div() calls.
use kael::prelude::*;

div()
    .flex()
    .flex_col()
    .gap_4()
    .p_4()
    .bg(theme.colors.surface)
    .rounded(theme.radii.md)
    .child(div().text_sm().child("Hello, Kael!"))

Composing children

Every ParentElement — including div() — exposes three composition helpers:
MethodSignaturePurpose
.child()fn child(self, child: impl IntoElement) -> SelfAppend a single child
.children()fn children(self, children: impl IntoIterator<Item = impl IntoElement>) -> SelfAppend multiple children from any iterator
.when()fn when(self, condition: bool, then: impl FnOnce(Self) -> Self) -> SelfConditionally apply a modifier or add children
.when_some()fn when_some<T>(self, option: Option<T>, then: impl FnOnce(Self, T) -> Self) -> SelfApply a modifier only when an Option is Some
div()
    .children(items.iter().map(|item| {
        div().child(item.label.clone())
    }))
    .when(is_loading, |el| el.opacity(0.5))
    .when_some(error_message.as_ref(), |el, msg| {
        el.child(div().text_color(theme.colors.error).child(msg.clone()))
    })

Image: img()

img() renders raster images from a URL, embedded asset path, file-system path, or a pre-cached RenderImage. The element handles async loading, animated GIFs and WebP, and participates in an optional shared ImageCache.
// From a remote URL
img("https://example.com/photo.jpg")
    .w_32()
    .h_32()
    .object_fit(ObjectFit::Cover)
    .rounded(theme.radii.md)

// From an embedded asset path
img("assets/logo.png")
    .w_24()
    .h_24()
ImageSource accepts &str, String, SharedString, PathBuf, Arc<Path>, or a SharedUri — the constructor sniffs whether the string looks like a URI and routes it accordingly. You can also supply a fully custom loading closure:
img(ImageSource::Custom(Arc::new(|window, cx| {
    // return Option<Result<Arc<RenderImage>, ImageCacheError>>
    Some(Ok(my_render_image.clone()))
})))
img() shows nothing while loading and nothing on error by default. Use .with_loading() and .with_fallback() (available on the Lottie element — see below) as a pattern to adopt in custom wrappers.

SVG: svg()

svg() renders vector graphics from a file path. It participates in the same Interactivity system as div(), so you can attach click handlers, tooltips, and accessibility attributes.
// Construct an SVG element
pub fn svg() -> Svg

// Set the path to the SVG asset
impl Svg {
    pub fn path(self, path: impl Into<SharedString>) -> Self
    pub fn with_transformation(self, transformation: Transformation) -> Self
}
svg()
    .path("assets/icons/chevron-right.svg")
    .w_4()
    .h_4()
    .text_color(theme.colors.foreground)
Use icon() instead of svg() when your icons are baked into the build-time icon atlas — it is more efficient because the atlas is uploaded to the GPU once.

Icon: icon()

icon() renders named icons from Kael’s generated icon atlas. Icons are resolved by name at paint time, so there is no per-call file I/O.
// Construct an icon from the atlas
pub fn icon(name: impl Into<SharedString>) -> Icon
icon("arrow-right")
    .w_4()
    .h_4()
    .text_color(theme.colors.primary)

icon("check-circle")
    .w_5()
    .h_5()

Canvas: canvas()

canvas() provides direct access to Kael’s GPU paint pipeline without defining a full custom element. It supports two calling conventions:

Canvas drawing API

When you use DrawContext, you have access to the following immediate-mode drawing primitives:
// Returns canvas-local bounds and size
ctx.bounds() -> Bounds<Pixels>
ctx.size()   -> Size<Pixels>

// Rectangles
ctx.fill_rect(bounds, fill)
ctx.fill_rounded_rect(bounds, radii, fill)

// Circles
ctx.fill_circle(center, radius, fill)
ctx.stroke_circle(center, radius, stroke)

// Lines and paths
ctx.stroke_line(from, to, stroke)
ctx.fill_path(path, fill)
ctx.stroke_path(path, stroke)

// Transforms
ctx.with_transform(matrix, |ctx| { ... })
Construct a Stroke value with the stroke() helper:
use kael::prelude::*;

let s = stroke(px(2.), rgb(0x3b82f6))
    .cap(LineCap::Round)
    .join(LineJoin::Round);

ctx.stroke_line(point(px(0.), px(0.)), point(px(100.), px(100.)), s);
StrokeDash lets you draw dashed lines:
let dashed = Stroke {
    width: px(1.),
    color: theme.colors.border,
    dash: Some(StrokeDash {
        segments: vec![px(4.), px(4.)],
        offset: px(0.),
    }),
    cap: LineCap::Butt,
    join: LineJoin::Miter,
};

Label: label()

label() is an accessible text primitive that optionally forwards focus to another control when clicked, making it ideal for pairing with form fields.
pub fn label(id: impl Into<ElementId>) -> Label

impl Label {
    pub fn text(self, text: impl Into<SharedString>) -> Self
    pub fn for_focus_handle(self, focus_handle: FocusHandle) -> Self
}
// Plain label
label("username-label")
    .text("Username")
    .text_sm()
    .text_color(theme.colors.foreground)

// Label that focuses an input when clicked
label("email-label")
    .text("Email address")
    .for_focus_handle(email_input_focus.clone())

Lottie animation: lottie()

lottie() renders .lottie or .json Lottie animations using an off-thread renderer with frame prefetching. Frames are cached in the GPU atlas.
pub fn lottie(source: impl Into<LottieSource>) -> Lottie

impl Lottie {
    pub fn autoplay(self) -> Self
    pub fn loop_mode(self, loop_mode: LoopMode) -> Self
    pub fn loop_forever(self) -> Self
    pub fn ping_pong(self) -> Self
    pub fn prefetch_frames(self, prefetch_frames: usize) -> Self
    pub fn object_fit(self, object_fit: ObjectFit) -> Self
    pub fn with_loading(self, loading: impl Fn() -> AnyElement + 'static) -> Self
    pub fn with_fallback(self, fallback: impl Fn() -> AnyElement + 'static) -> Self
}
lottie("assets/confetti.lottie")
    .autoplay()
    .loop_forever()
    .w_48()
    .h_48()
    .with_loading(|| {
        div().w_48().h_48().bg(theme.colors.surface).into_any()
    })
    .with_fallback(|| {
        icon("image-off").w_8().h_8().into_any()
    })
Use .ping_pong() for idle-state animations that should smoothly reverse without a hard cut.

Overlay elements

Kael provides three overlay primitives for floating UI. These are covered in detail in the Overlays API reference, but a quick summary:
ConstructorSignaturePurpose
modal()modal(id, open: bool)Full-screen blocking overlay with dismiss-on-backdrop-click
popover()popover(id, open: bool)Anchored floating panel that dismisses on outside interaction
anchored()anchored()Low-level anchor primitive for positioning floating content relative to a target element
// Show a modal when `show_dialog` is true
modal("confirm-dialog", show_dialog)
    .child(
        div()
            .p_6()
            .child("Are you sure?")
    )

// A popover anchored to a trigger
popover("options-menu", menu_open)
    .child(options_panel())

Build docs developers (and LLMs) love