Virtual Scrolling
Relevant source files
The following files were used as context for generating this wiki page:
Virtual Scrolling renders only the visible portion of a large dataset to maintain high performance and low memory usage in the browser. It uses a sparse data structure to manage non-contiguous items, which is essential for handling large IMAP mailboxes where data is fetched incrementally over a network.
Sources: crates/mailiner-app/src/components/virtual_scroll.rs:1-12, AGENTS.md:10-15
Architecture and Core Logic
The virtual scrolling system consists of a reactive Dioxus component, a specialized sparse list data structure, and viewport calculation logic.
SparseList Data Structure
The SparseList<T> manages items using a BTreeMap<usize, T>. It stores only loaded indices to conserve memory while maintaining a logical total_count that reflects the full size of the remote dataset (e.g., total messages in an IMAP folder).
- Hole Detection: The list identifies missing ranges within a specific viewport to signal the need for data fetching.
- Index Management: It supports relocating items, shifting indices after removals, and prepending items while keeping the logical structure intact.
- Eviction: It drops cached items that fall outside the buffered viewport when a configurable
max_cachedlimit is reached.
Sources: crates/mailiner-app/src/components/virtual_scroll.rs:13-160
Viewport Management
The ViewportInfo struct calculates the visible range based on scroll position, container height, and fixed item height.
The calculation logic determines the first_visible_index and last_visible_index, then extends these by a buffer_size to ensure smooth scrolling and pre-fetching of upcoming data.
Sources: crates/mailiner-app/src/components/virtual_scroll.rs:162-205
Component Implementation
The VirtualScroll component is the primary UI element for rendering large lists. It uses a "spacer" div to create a scrollable area matching the height of the full dataset, even if most items are not yet loaded.
Rendering Logic
- Spacer Element: A relative-positioned div with a height equal to
total_count * item_height. - Content Container: An absolute-positioned div that uses
translateYto position the visible items correctly within the spacer. - Placeholders: If an item in the visible range is missing from the
SparseList, the component renders a loading skeleton.
Sources: crates/mailiner-app/src/components/virtual_scroll.rs:328-375, crates/mailiner-app/assets/main.css:1040-1070
Data Flow
The component reacts to changes in the underlying SparseList and scroll events.
Configuration and Usage
The MessageList component utilizes VirtualScroll to display emails. It defines specific constants for item height and caching limits.
| Prop | Type | Description | Default/Value |
|---|---|---|---|
item_height | f64 | Fixed height of each row in pixels | 52.0 |
buffer_size | usize | Items to pre-render above/below viewport | 5 |
max_cached | usize | Maximum items to keep in memory | 500 |
debounce_ms | Option<u32> | Wait time before fetching on scroll | 100ms |
Sources: crates/mailiner-app/src/components/emailnavigation/messagelist.rs:24-28, crates/mailiner-app/src/components/virtual_scroll.rs:232-246
Selection and Keyboard Navigation
The system provides utilities to maintain selection and focus during list modifications:
index_after_removal: Calculates which index should be selected after a row is removed, preferring the item that slides into the vacant slot.adjacent_index: Determines the next logical index for keyboard navigation, clamping results to the list boundaries.scroll_row_into_view: Programmatically scrolls the container to ensure a specific index is visible, typically triggered byreveal_indexchanges.
Sources: crates/mailiner-app/src/components/virtual_scroll.rs:207-230, crates/mailiner-app/src/components/virtual_scroll.rs:388-410
Performance Techniques
To ensure the application remains responsive under WASM, the virtual scrolling implementation employs several techniques:
- Shimmer Animation: Uses a CSS linear-gradient animation on placeholders to provide visual feedback during data fetching.
- Pending Range Tracking: Maintains a list of "in-flight" fetch requests to prevent duplicate network calls for the same indices.
- ResizeObserver: Measures the actual content box height of the container to calculate visible rows accurately, handling sub-pixel noise to avoid unnecessary re-calculations.
- Smooth Scrolling: Implements a
next_smooth_targetalgorithm that coalesces rapid scroll inputs (within 350ms) to prevent animation restarts and jitter.
Sources: crates/mailiner-app/src/components/virtual_scroll.rs:288-326, crates/mailiner-app/src/components/messageview.rs:90-115, AGENTS.md:12-15
Virtual Scrolling is a critical component for the mail client, allowing it to handle mailboxes with thousands of messages while maintaining a constant memory footprint and smooth user interface interactions.