Skip to main content

Crate fui

Crate fui 

Source
Expand description

§FUI-RS - retained Rust UI for WebAssembly and native desktop

FUI-RS is the web-born retained-mode Rust UI SDK for EffinDOM. One application model runs in the browser through WebAssembly and as a real native macOS, Windows, or Linux desktop application. Native applications embed neither Chromium nor a system WebView.

The SDK provides retained controls, layout nodes, text input, overlays, custom drawing, host services, workers, accessibility semantics, routing support, and application lifecycle macros.

The Cargo package is named fui-rs, while application code imports its library as fui:

cargo add fui-rs --rename fui

§Quickstart

Create a native, web, or universal application with cargo-fui:

# Install stable Rust and Cargo once
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"

cargo install --locked cargo-fui
cargo fui new my-app --target universal
cd my-app
cargo fui dev

Choose native for desktop only, web for browser only, or universal for a shared retained UI with explicit native and web adapters. Native-only projects do not require Node.js. cargo fui build --release creates optimised output and cargo fui package emits DMG, MSIX, or AppImage packages.

For a browser-only routed application with one independently built WASM module per route, use the npm scaffolder:

npx @effindomv2/create-fui-rs-app my-routed-app -- --template routed
cd my-routed-app
npm install
npm run dev

Install Binaryen to make release builds run wasm-opt. Development builds do not require it.

Application setup, retained-mode guidance, and entrypoint examples are covered in the FUI-RS developer quickstart.

§Minimal app

use fui::prelude::*;

fn build_page() -> FlexBox {
    ui! {
        column().fill_size().padding(24.0, 24.0, 24.0, 24.0) {
            text("Hello from Rust"),
            button("Click me").on_click(|_| {}),
        }
    }
}

fui_app!(FlexBox, build_page);

§Documentation

The live routed demo demonstrates the browser/npm workflow. Native and packaging claims are validated separately by cargo-fui fixtures and native platform tests.

§Rich text

Use rich_text! to create retained rich text without manually constructing a span vector. String literals become spans, braced expressions provide dynamic text, and span => expression accepts an existing RichTextSpan:

use fui::prelude::*;

let value = 42;
let suffix = span("!").underline();
let label = rich_text![
    "Current value: ".italic(),
    { format!("{value}") }.bold().text_color(rgb(0x3a, 0xc5, 0x6c)),
    span => suffix,
]
.font_size(18.0);

§SDK docs

§Contributing to FUI-RS

The commands above are for developers building applications with the published FUI-RS SDK. Contributors working on the SDK, EffinDom runtime, browser bridge, or repository demos should follow the FUI-RS contributor quickstart. It covers the standalone repository toolchain, SDK build, lint, and test lanes.

§What is included

AreaStatus
Retained app lifecycle macrosAvailable
ui! mixed child tree macroAvailable
fui_component! retained component delegationAvailable
Flex/Grid layout nodesAvailable
Text, rich text, image, SVGAvailable
Buttons, toggles, slider, dropdown, comboboxAvailable
TextInput/TextAreaAvailable
Context menu, popup, dialog, tooltipAvailable
Selection, mobile text handles, context toolbarAvailable
ScrollView, ScrollBox, VirtualListAvailable
Custom drawing, paths, dynamic bitmaps, offscreen composition, retained rasterization, and timersAvailable on web and native
Native and browser platform adaptersAvailable
Browser file/fetch bridgesAvailable in browser applications
First-party background workersAvailable on web and native
Host services/events generator supportAvailable

§Recycled virtual-list rows

VirtualList creates a fixed retained row pool. Use item_template once to construct typed row state, then update that state from on_bind_item whenever a pool slot is assigned a new item index:

use fui::prelude::*;

struct ContactRow {
    name: TextNode,
}

let contacts = virtual_list(10_000, 28.0)
    .item_template(|container| {
        let name = text("");
        container.child(&name);
        ContactRow { name }
    });
contacts.on_bind_item(|row, index| {
    row.name.text(format!("Contact {index}"));
});

The template is not rerun while scrolling. Do not key recycled rows by pointer or create controls inside on_bind_item.

§Scrollbar styling

Apply common scrollbar chrome without leaving fluent ScrollBox construction:

use fui::prelude::*;

let content = scroll_box().scrollbar_style(
    ScrollBarStyle::new()
        .track_width(10.0)
        .thumb_width(7.0)
        .thumb_corner_radius(3.5),
);

Use vertical_scrollbar() or horizontal_scrollbar() afterward for an axis-specific override.

§Host-event lifetime

Generated on_* host-event functions return HostEventSubscription. Retain the guard for exactly as long as the handler should remain active; dropping it unsubscribes automatically. Replacing a handler is generation-safe, so dropping an older guard cannot remove its replacement.

§Worker entrypoints

Enable the worker-runtime feature, implement Default + WorkerJob, and let the SDK emit resumable entries plus the shared callback-buffer ABI:

use fui::prelude::*;

#[derive(Default)]
struct PrimeJob {
    state: WorkerJobState,
}

impl WorkerJob for PrimeJob {
    fn state(&mut self) -> &mut WorkerJobState { &mut self.state }
    fn run(&mut self) { self.complete("done"); }
}

fui_worker!(primeWorker => PrimeJob);

Declare each Worker artifact, native Cargo manifest, and exported entry in fui.toml. Application code then uses the same identity on every target:

let worker = Worker::new("./workers.wasm", "primeWorker")
    .on_complete(|event| println!("{}", event.result))
    .start("input");

On the web, cargo-fui compiles the worker crate to the declared Worker WASM artifact and runs it in a browser Worker. On native desktop, the same worker crate is linked into the application and the artifact/entry pair resolves through a generated registry onto a dedicated thread; native does not load workers.wasm from disk. Cancellation is cooperative, so long-running jobs must yield or check cancellation regularly. Worker callbacks are delivered on the application UI thread.

§Architecture

FUI-RS builds retained Rust UI objects against the shared EffinDom runtime. Native hosts execute that runtime directly through platform adapters. On the web, Rust app WASM and the UI runtime WASM are separate modules; strings and command data cross the browser bridge through explicit UTF-8/runtime ABI calls.

Retained controls are cheap clone handles. Cloning a control gives another Rust handle to the same retained UI object.

FUI-RS maps retained inheritance to capability traits. Node supplies the universal retained/event surface; FlexBox-derived visuals additionally expose LayoutSurface, BoxStyleSurface, FlexLayoutSurface, and ChildContainerSurface. TextSurface covers Text and RichText, while TextEditorSurface covers TextInput and TextArea.

Use on_pointer_click(...) for raw routed pointer input. Use on_pointer_double_click(...) and on_pointer_triple_click(...) for exact raw multi-click gestures. Button, Checkbox, RadioButton, and Switch expose count-free on_click(...) semantic activation for supported pointer and keyboard input.

§Project status

FUI-RS is feature-rich early access. Its retained SDK, web and native hosts, controls, text editing, accessibility projection, custom drawing, and packaging workflow are usable today, but public APIs remain pre-1.0 and may change incompatibly.

Current platform limits:

  • Accessibility projection is implemented through DOM/ARIA on the web, NSAccessibility on macOS, Microsoft UI Automation on Windows, and AT-SPI on Linux. Broad compatibility testing across screen readers, browser combinations, and Linux desktop environments remains early.
  • iOS and Android are not currently supported.
  • Find-on-page is implemented through retained find for the normal desktop shortcut and projected semantic text for mobile or explicitly invoked browser-native find. Browser-native highlights can render with a slightly different DOM font from the canvas text.
  • The third-party control and integration ecosystem is new.

Try the live demo, then open a discussion or issue if a real application is blocked by a missing capability.

§License

AGPL-3.0-only, or commercial license. See COMMERCIAL.md.

Re-exports§

pub use animation::animate_color;
pub use animation::animate_color_with;
pub use animation::animate_float;
pub use animation::animate_float_with;
pub use animation::get_animation_manager;
pub use animation::reset_animations;
pub use animation::tick_animations;
pub use animation::Animation;
pub use animation::AnimationManager;
pub use animation::AnimationTiming;
pub use animation::Easing;
pub use animation::Easings;
pub use app::Application;
pub use app::ApplicationRegistration;
pub use app::ManagedApplication;
pub use app::PageZoomMode;
pub use bitmap::Bitmap;
pub use bitmap::BitmapTextReadyEventArgs;
pub use color::hsl_to_color;
pub use color::mix_color;
pub use color::rgb;
pub use color::rgba;
pub use color::with_alpha;
pub use controls::anti_selection_area;
pub use controls::anti_selection_area;
pub use controls::button;
pub use controls::button;
pub use controls::checkbox;
pub use controls::checkbox;
pub use controls::combo_box;
pub use controls::context_menu;
pub use controls::context_menu;
pub use controls::create_default_button_presenter;
pub use controls::create_default_checkbox_indicator_presenter;
pub use controls::create_default_dropdown_chevron_presenter;
pub use controls::create_default_dropdown_field_presenter;
pub use controls::create_default_dropdown_option_row_presenter;
pub use controls::create_default_radio_indicator_presenter;
pub use controls::create_default_slider_presenter;
pub use controls::create_default_switch_indicator_presenter;
pub use controls::create_default_text_input_presenter;
pub use controls::dialog;
pub use controls::dialog;
pub use controls::dropdown;
pub use controls::dropdown;
pub use controls::form;
pub use controls::form;
pub use controls::popup;
pub use controls::popup;
pub use controls::progress_bar;
pub use controls::progress_bar;
pub use controls::radio_button;
pub use controls::radio_button;
pub use controls::radio_group;
pub use controls::radio_group;
pub use controls::selection_area;
pub use controls::selection_area;
pub use controls::slider;
pub use controls::slider;
pub use controls::switch;
pub use controls::switch;
pub use controls::tab_item;
pub use controls::tab_view;
pub use controls::tab_view;
pub use controls::text_area;
pub use controls::text_area;
pub use controls::text_input;
pub use controls::text_input;
pub use controls::AntiSelectionArea;
pub use controls::Button;
pub use controls::ButtonColors;
pub use controls::ButtonPresenter;
pub use controls::ButtonTemplate;
pub use controls::ButtonVisualState;
pub use controls::CheckState;
pub use controls::Checkbox;
pub use controls::CheckboxChangedEventArgs;
pub use controls::CheckboxIndicatorPresenter;
pub use controls::CheckboxIndicatorTemplate;
pub use controls::CheckboxIndicatorVisualState;
pub use controls::ClickEventArgs;
pub use controls::ComboBox;
pub use controls::ComboBoxChangedEventArgs;
pub use controls::ComboBoxCommitMode;
pub use controls::ComboBoxFilterMode;
pub use controls::ComboBoxItem;
pub use controls::ContextMenu;
pub use controls::ContextMenuAction;
pub use controls::ContextMenuAppearance;
pub use controls::ContextMenuItemAppearance;
pub use controls::ContextMenuVisibilityChangedEventArgs;
pub use controls::DefaultButtonTemplate;
pub use controls::DefaultCheckboxIndicatorTemplate;
pub use controls::DefaultDropdownChevronTemplate;
pub use controls::DefaultDropdownFieldTemplate;
pub use controls::DefaultDropdownOptionRowTemplate;
pub use controls::DefaultRadioIndicatorTemplate;
pub use controls::DefaultSliderTemplate;
pub use controls::DefaultSwitchIndicatorTemplate;
pub use controls::DefaultTextInputTemplate;
pub use controls::Dialog;
pub use controls::DialogAppearance;
pub use controls::DialogShownEventArgs;
pub use controls::Dropdown;
pub use controls::DropdownChangedEventArgs;
pub use controls::DropdownChevronMetrics;
pub use controls::DropdownChevronPresenter;
pub use controls::DropdownChevronTemplate;
pub use controls::DropdownChevronVisualState;
pub use controls::DropdownColors;
pub use controls::DropdownFieldMetrics;
pub use controls::DropdownFieldPresenter;
pub use controls::DropdownFieldTemplate;
pub use controls::DropdownFieldVisualState;
pub use controls::DropdownItem;
pub use controls::DropdownOptionRowMetrics;
pub use controls::DropdownOptionRowPresenter;
pub use controls::DropdownOptionRowTemplate;
pub use controls::DropdownOptionRowVisualState;
pub use controls::DropdownSizing;
pub use controls::Form;
pub use controls::LabeledControlColors;
pub use controls::LabeledControlSizing;
pub use controls::MenuItem;
pub use controls::NavLinkInteractionState;
pub use controls::NavigateEventArgs;
pub use controls::OverlayBackdropAppearance;
pub use controls::Popup;
pub use controls::PopupAppearance;
pub use controls::PressableIndicatorMetrics;
pub use controls::PressableIndicatorPresenter;
pub use controls::PressableIndicatorVisualState;
pub use controls::ProgressBar;
pub use controls::ProgressBarColors;
pub use controls::ProgressBarSizing;
pub use controls::RadioButton;
pub use controls::RadioButtonChangedEventArgs;
pub use controls::RadioGroup;
pub use controls::RadioGroupChangedEventArgs;
pub use controls::RadioIndicatorPresenter;
pub use controls::RadioIndicatorTemplate;
pub use controls::RadioIndicatorVisualState;
pub use controls::SelectionArea;
pub use controls::Slider;
pub use controls::SliderChangedEventArgs;
pub use controls::SliderColors;
pub use controls::SliderPresenter;
pub use controls::SliderPresenterMetrics;
pub use controls::SliderSizing;
pub use controls::SliderTemplate;
pub use controls::SliderVisualState;
pub use controls::SurfaceAppearance;
pub use controls::Switch;
pub use controls::SwitchChangedEventArgs;
pub use controls::SwitchIndicatorPresenter;
pub use controls::SwitchIndicatorTemplate;
pub use controls::SwitchIndicatorVisualState;
pub use controls::TabContentFactory;
pub use controls::TabItem;
pub use controls::TabSelectionChangedEventArgs;
pub use controls::TabView;
pub use controls::TextArea;
pub use controls::TextEditorSurface;
pub use controls::TextInput;
pub use controls::TextInputColors;
pub use controls::TextInputPresenter;
pub use controls::TextInputTemplate;
pub use controls::TextInputVisualState;
pub use controls::DEFAULT_BUTTON_TEMPLATE;
pub use controls::DEFAULT_CHECKBOX_INDICATOR_TEMPLATE;
pub use controls::DEFAULT_DROPDOWN_CHEVRON_TEMPLATE;
pub use controls::DEFAULT_DROPDOWN_FIELD_TEMPLATE;
pub use controls::DEFAULT_DROPDOWN_OPTION_ROW_TEMPLATE;
pub use controls::DEFAULT_RADIO_INDICATOR_TEMPLATE;
pub use controls::DEFAULT_SLIDER_TEMPLATE;
pub use controls::DEFAULT_SWITCH_INDICATOR_TEMPLATE;
pub use controls::DEFAULT_TEXT_INPUT_TEMPLATE;
pub use drag_drop::DragCompletedEventArgs;
pub use drag_drop::DragDataObject;
pub use drag_drop::DragDropEffects;
pub use drag_drop::DragEventArgs;
pub use drag_drop::DragSession;
pub use drag_drop::DropProposal;
pub use drawing::DrawContext;
pub use drawing::Paint;
pub use drawing::Path;
pub use event::FocusChangedEventArgs;
pub use event::GestureEventArgs;
pub use event::GestureEventKind;
pub use event::GestureEventPhase;
pub use event::GestureIntent;
pub use event::KeyEventArgs;
pub use event::LongPressEventArgs;
pub use event::PointerButton;
pub use event::PointerButtons;
pub use event::PointerEventArgs;
pub use event::PointerType;
pub use event::SelectionChangedEventArgs;
pub use event::TextChangedEventArgs;
pub use event::WheelEventArgs;
pub use external_drop::ExternalDropEventArgs;
pub use external_drop::ExternalDropItemInfo;
pub use external_drop::ExternalDropItemKind;
pub use fetch::Fetch;
pub use fetch::FetchErrorEventArgs;
pub use fetch::FetchRequest;
pub use fetch::FetchResponse;
pub use file::BrowserFile;
pub use file::BrowserFileWriter;
pub use file::File;
pub use file::FileCapabilities;
pub use file::FileErrorEventArgs;
pub use file::FileOpenEventArgs;
pub use file::FileOpenRequest;
pub use file::FileReadChunk;
pub use file::FileRequestGuard;
pub use file::FileSaveMode;
pub use file::FileSaveRequest;
pub use file::FileSaveResult;
pub use file::FileWorkerProcessProgress;
pub use file::FileWorkerProcessRequest;
pub use file::FileWorkerProcessResult;
pub use file::FileWriteProgress;
pub use frame_scheduler::mark_needs_commit;
pub use frame_scheduler::on_loaded;
pub use frame_scheduler::LoadedEventArgs;
pub use frame_signal::frame_time_signal;
pub use frame_signal::FrameTimeSignalHandle;
pub use host_events::HostEventSubscription;
pub use image_sampling::ImageSampling;
pub use image_sampling::ImageSamplingMode;
pub use node::auto;
pub use node::column;
pub use node::custom_drawable;
pub use node::fill;
pub use node::flex_box;
pub use node::grid;
pub use node::image;
pub use node::pct;
pub use node::portal;
pub use node::px;
pub use node::row;
pub use node::scroll_box;
pub use node::scroll_view;
pub use node::svg;
pub use node::text;
pub use node::viewport_height;
pub use node::viewport_width;
pub use node::virtual_list;
pub use node::Border;
pub use node::BoxStyleSurface;
pub use node::Child;
pub use node::ChildContainerSurface;
pub use node::ContextMenuEventArgs;
pub use node::Corners;
pub use node::CustomDrawable;
pub use node::DrawableInvalidator;
pub use node::EdgeInsets;
pub use node::FlexBox;
pub use node::FlexBoxSurface;
pub use node::FlexLayoutSurface;
pub use node::GradientStop;
pub use node::Grid;
pub use node::GridTrack;
pub use node::HasFlexBoxRoot;
pub use node::HasTextNode;
pub use node::Image;
pub use node::ImageNode;
pub use node::LayoutSurface;
pub use node::Length;
pub use node::Node;
pub use node::Portal;
pub use node::PresenterHostStyle;
pub use node::ScrollBar;
pub use node::ScrollBarStyle;
pub use node::ScrollBarVisibility;
pub use node::ScrollBox;
pub use node::ScrollState;
pub use node::ScrollView;
pub use node::Shadow;
pub use node::Svg;
pub use node::SvgNode;
pub use node::Text;
pub use node::TextContentSurface;
pub use node::TextEditingSurface;
pub use node::TextEventSurface;
pub use node::TextLayoutSurface;
pub use node::TextNode;
pub use node::TextSelectionSurface;
pub use node::TextSurface;
pub use node::TextTypographySurface;
pub use node::ThemeBindable;
pub use node::VirtualList;
pub use retained_view::retained_view;
pub use retained_view::RetainedView;
pub use text::span;
pub use text::DynamicTextLayout;
pub use text::DynamicTextOverflow;
pub use text::RichText;
pub use text::RichTextSpan;
pub use text::TextLayout;
pub use text::TextLayoutReadyEventArgs;
pub use text::TextMetrics;
pub use theme::bind_theme;
pub use theme::current_theme;
pub use theme::default_dark_theme;
pub use theme::default_light_theme;
pub use theme::generate_theme;
pub use theme::is_dark_mode;
pub use theme::is_using_system_theme;
pub use theme::set_accent_color;
pub use theme::subscribe;
pub use theme::use_custom_theme;
pub use theme::use_system_theme;
pub use theme::Colors;
pub use theme::ContextMenuItemTheme;
pub use theme::ContextMenuTheme;
pub use theme::Fonts;
pub use theme::Spacing;
pub use theme::Theme;
pub use theme::ToolTipTheme;
pub use timers::cancel_timeout;
pub use timers::set_timeout;
pub use timers::TimerHandle;
pub use tool_tip::ToolTip;
pub use transitions::NodeTransitions;
pub use typography::FontFace;
pub use typography::FontFaceLoadedEventArgs;
pub use typography::FontFamily;
pub use typography::FontStack;
pub use typography::FontStackLoadedEventArgs;
pub use typography::FontStyle;
pub use typography::FontWeight;
pub use typography::FontsLoadedEventArgs;
pub use viewport::viewport_height_signal;
pub use viewport::viewport_width_signal;
pub use viewport::ViewportSignalHandle;
pub use worker::Worker;
pub use worker::WorkerCompletedEventArgs;
pub use worker::WorkerErrorEventArgs;
pub use worker::WorkerProgressEventArgs;
pub use worker_job::WorkerJob;
pub use worker_job::WorkerJobState;
pub use worker_runtime::file_read_chunk;
pub use worker_runtime::file_worker_write_chunk;
pub use worker_runtime::reset_worker_runtime;
pub use worker_runtime::WorkerRuntime;
pub use assets::*;
pub use debug::*;
pub use logger::*;
pub use navigation::*;
pub use persisted::*;
pub use platform::*;

Modules§

animation
app
assets
bitmap
color
controls
debug
drag_drop
drawing
event
external_drop
fetch
file
frame_scheduler
frame_signal
host_events
host_services
image_sampling
logger
navigation
node
persisted
platform
prelude
retained_view
text
theme
timers
tool_tip
transitions
typography
viewport
worker
worker_host_services
worker_job
worker_runtime

Macros§

children
fui_app
Defines the standard FUI-RS application lifecycle exports.
fui_component
Delegates Node and HasFlexBoxRoot to a retained component’s root.
fui_managed_app
Defines FUI-RS application lifecycle exports with custom root projection and optional mount/dispose hooks.
fui_worker
rich_text
Builds retained rich text with fluent span styling.
tab_items
Builds a Vec<TabItem> from owned fluent items or borrowed named items.
ui

Enums§

AlignItems
AlignSelf
BorderStyle
CursorStyle
FlexDirection
FlexWrap
GridUnit
JustifyContent
KeyEventType
KeyModifier
ObjectFit
Orientation
PointerEventType
PositionType
SemanticCheckedState
SemanticRole
TextAlign
TextOverflow
TextVerticalAlign
Unit
Visibility

Traits§

Configure

Functions§

current_route
show_keyboard_focus_for_key_event

Type Aliases§

Subscription