Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Lists & Data

High-performance list components with virtualization for rendering thousands of items.


UniformList

Highest-performance list for items of equal height. Only renders visible items — handles 100K+ items smoothly:

#![allow(unused)]
fn main() {
use kael::{uniform_list, UniformListScrollHandle};

let scroll_handle = UniformListScrollHandle::new();

uniform_list(
    "log-entries",
    self.entries.len(),
    {
        let entries = self.entries.clone();
        move |range, _window, _cx| {
            entries[range.clone()]
                .iter()
                .map(|entry| {
                    div()
                        .px_3()
                        .py_1()
                        .text_sm()
                        .child(entry.message.clone())
                        .into_any_element()
                })
                .collect()
        }
    },
)
.track_scroll(scroll_handle.clone())
}

When to use: Log viewers, file lists, data tables — any list where every row has the same height.


List

Flexible list with alignment and overflow handling:

#![allow(unused)]
fn main() {
use kael::list;

// Basic list
list()
    .child(div().child("Item 1"))
    .child(div().child("Item 2"))
    .child(div().child("Item 3"))
}

RecyclingList

Virtualized list for items with different heights. Recycles DOM nodes for performance:

#![allow(unused)]
fn main() {
use kael::recycling_list;

recycling_list(
    "messages",
    self.messages.len(),
    move |index, _window, _cx| {
        let msg = &messages[index];
        div()
            .p_3()
            .child(div().font_weight(FontWeight::BOLD).child(msg.sender.clone()))
            .child(div().text_sm().child(msg.body.clone()))
            .into_any_element()
    },
)
}

When to use: Chat messages, feed items — lists where rows vary in height.


SortableList

Drag-to-reorder list with auto-scroll and insertion indicator:

#![allow(unused)]
fn main() {
use kael::sortable_list;

sortable_list(
    "layers",
    self.layers.len(),
    {
        let layers = self.layers.clone();
        move |index, _window, _cx| {
            div()
                .px_3()
                .py_2()
                .child(layers[index].name.clone())
                .into_any_element()
        }
    },
)
.on_reorder({
    let entity = entity.clone();
    move |from, to, _window, cx| {
        entity.update(cx, |this, cx| {
            let item = this.layers.remove(from);
            this.layers.insert(to, item);
            cx.notify();
        });
    }
})
}

When to use: Layer panels, playlist editors, kanban columns — anywhere users reorder items by dragging.


ScrollBar

Kael provides automatic scrollbars for any element with overflow_y_scroll() or overflow_y_auto() and a tracked ScrollHandle. The scrollbar appears as a native-style dark rounded thumb when content overflows — no extra code needed (see Layout & Styling).

For custom scroll bar rendering, use the explicit scroll_bar() widget:

#![allow(unused)]
fn main() {
use kael::scroll_bar;

scroll_bar(scroll_handle.clone())
    .render_with(|state, bounds, window, _cx| {
        // Custom scroll bar rendering
        // state.thumb_bounds, state.dragging
    })
}

Patterns

Data table with uniform_list

#![allow(unused)]
fn main() {
struct DataTable {
    rows: Vec<Row>,
    columns: Vec<Column>,
    scroll: UniformListScrollHandle,
}

impl Render for DataTable {
    fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
        let columns = self.columns.clone();
        let rows = self.rows.clone();

        div().flex().flex_col().size_full()
            .child(self.render_header())
            .child(
                uniform_list("table-body", rows.len(), move |range, _w, _cx| {
                    rows[range.clone()].iter().map(|row| {
                        div().flex().flex_row()
                            .children(columns.iter().map(|col| {
                                div().w(px(col.width)).px_2().py_1()
                                    .child(row.get(&col.key).clone())
                            }))
                            .into_any_element()
                    }).collect()
                })
                .track_scroll(self.scroll.clone())
            )
    }
}
}