Dioxus 0.6.0 Alpha
Dioxus 0.6 includes improvements to several areas of dioxus. The highlights are:
- Asset improvements
- Head elements
- RSX autocomplete
- Improved hot reloading
- Suspense and streaming
- Error boundaries
- A new TUI!
- Documentation improvements
- Blitz rewrite
Asset Stabilization
We introduced our new asset system, Manganis, in an alpha state with the 0.5 release. Dioxus 0.6 stabilizes the asset system and fixes several bugs and performance issues. You can try out the new linker based asset system by including an asset!
anywhere in your code. It will automatically be optimized and bundled across all platforms:
rsx! {
img { src: asset!("./assets/myimg.png") }
}
Head Elements
In addition to the Manganis asset system, dioxus 0.6 includes a new way to include assets into your html. The new Script
, Link
, Style
, and Meta
components let you link to assets anywhere in your html. These components will automatically be hoisted into the <head>
across all platforms and deduplicated by the source:
#[component]
fn MyStyledComponent() -> {
rsx! {
head::Link {
rel: "stylesheet",
href: asset!("./assets/style.css")
}
"This component is styled"
}
}
Autocomplete and improved errors for RSX
RSX now supports autocomplete everywhere. In addition to expressions, elements, components and attributes now autocomplete correctly:
autocomplete.mov
The new version of RSX also features better error messages for incorrect markup:
Supercharged Hot Reloading
In 0.6, RSX hot reloading is much more consistent. You can move around and duplicate expressions anywhere in an rsx block or create new literals anywhere in an rsx block. This means you can now create new formatted text nodes, new formatted attributes or tweak properties on the fly without recompiling!
hot-reloading.mov
Suspense and Streaming
Async is a core component of any UI framework. Dioxus provides hooks to handle async state. You can start a future and handle the loading and resolved states within the component:
#[component]
fn Article() -> Element {
// Use resource starts a future in the background and returns the current state
let article = use_resource(fetch_article);
rsx! {
// You can match the state of the future to render either a loading state or the resolved state
match article() {
Some(article) => rsx! { "{article}" },
None => rsx! { p { "Loading..." } }
}
}
}
This works ok if you have a single future, but it quickly gets messy when combining many futures into one UI:
#[component]
fn Article() -> Element {
// Use resource starts a future in the background and returns the current state
let Some(title) = use_resource(fetch_title).cloned() else {
return rsx! { "loading..." }
};
let Some(article) = use_resource(fetch_article).cloned() else {
return rsx! { "loading..." }
};
let Some(category) = use_resource(move || article.title()).cloned() else {
return rsx! { "loading..." }
};
rsx! {
Title { "{title}" }
Body { category, article }
}
}
In addition to hooks, we need a way to display a different state when async is loading. Dioxus 0.6 introduces a new core primitive for async UI called suspense boundaries. A suspense boundary is a component that renders a placeholder when any child component is loading:
rsx! {
SuspenseBoundary {
fallback: |context: SuspenseContext| rsx! {
// Render a loading placeholder if any child component is suspended
"Loading..."
},
Article {}
}
}
In any child component, you can just bubble up the pending state with ?
to pause rendering until the future is finished:
#[component]
fn Article() -> Element {
let title = use_resource(fetch_title).suspend()?;
let article = use_resource(fetch_article).suspend()?;
let category = use_resource(move || article.title()).suspend()?;
// Since we bubbled up all the pending futures with `?` we can just
// handle the happy path in the component
rsx! {
Title { "{title}" }
Body { category, article }
}
}
Along with suspense boundaries, dioxus fullstack also supports streaming each suspense boundary in from the server. Instead of waiting for the whole page to load, dioxus fullstack streams in each chunk with the resolved futures as they finish:
streaming.mov
Error boundaries
0.6 also introduces error boundaries which let you display an error message if any child component runs into an error:
#[component]
fn Root() -> Element {
rsx! {
ErrorBoundary {
handle_error: |errors: ErrorContext| {
match errors.show() {
// Render the view the child component through with the error
Some(view) => view,
// Or a fallback if the error doesn't come with a view
None => rsx! {
pre {
color: "red",
"oops, we ran into an error\n{errors:#?}"
}
}
}
},
Contents {}
}
}
}
You can throw an error from any child component while rendering or handling events:
#[component]
fn Double(input: String) -> Element {
// You can use ? to throw an event during rendering
let parsed: f32 = input.parse()?;
let doubled = parsed * 2.0;
rsx! {
"{doubled}"
}
}
#[component]
fn DoubleButton(mut count: Signal<u8>) -> Element {
rsx! {
button {
onclick: move |_| {
// Errors can have an associated view which the error boundary can
// choose to show
let doubled = count().checked_mul(2).show(|_|
rsx! { "multiplying {count} by 2 would overflow the u8" }
)?;
count.set(doubled);
Ok(())
},
"Double!"
}
}
}
DX TUI
The Dioxus CLI has been rewritten to support a TUI with build progress, and multiple views for logs. It has shortcuts for common actions, and displays progress in both the TUI and the site as the project loads:
tui.mov
Blitz Rewrite
Blitz has been rewritten to use Firefox's browser engine, Stylo. The new version of Blitz is much more capable with proper accessibility support, IME support, and better text support. Blitz should be a drop in replacement for dioxus desktop for the small subset of HTML it supports. Keep in mind Blitz is still experimental and not ready for production use. You can try Blitz by adding dioxus_blitz from the git repo:
cargo add dioxus-blitz --git https://github.com/DioxusLabs/blitz
Launching your Dioxus app with the blitz renderer:
dioxus_blitz::launch(app);
Ergonomic tweaks
Dioxus 0.6 also includes a number of smaller ergonomic tweaks that should help dioxus feel a lot more consistent
Static Generation
Dioxus 0.6 splits out static generation into its own platform to make it easier to set up:
//! Static generation works out of the box with the router. Just add a router anywhere in your app and it will generate any static routes for you!
#![allow(unused)]
use dioxus::prelude::*;
// Generate all routes and output them to the static path
fn main() {
launch(|| {
rsx! {
Router::<Route> {}
}
});
}
#[derive(Clone, Routable, Debug, PartialEq)]
enum Route {
#[route("/")]
Home {},
#[route("/blog")]
Blog,
}
#[component]
fn Blog() -> Element {
rsx! {
Link { to: Route::Home {}, "Go to counter" }
table {
tbody {
for _ in 0..100 {
tr {
for _ in 0..100 {
td { "hello!" }
}
}
}
}
}
}
}
#[component]
fn Home() -> Element {
let mut count = use_signal(|| 0);
rsx! {
Link { to: Route::Blog {}, "Go to blog" }
div {
h1 { "High-Five counter: {count}" }
button { onclick: move |_| count += 1, "Up high!" }
button { onclick: move |_| count -= 1, "Down low!" }
}
}
}
Fullstack State
Fullstack state now propagates from the launch builder into server functions which makes it much easier to set up state that is shared throughout your application like a database pool:
fn main() {
LaunchBuilder::new().with_context(1234567890u32).launch(app);
}
#[server]
async fn get_server_data() -> Result<String, ServerFnError> {
let FromContext(context): FromContext<u32> = extract().await?;
Ok(format!("the context was {context}"))
}
Callbacks
Dioxus 0.6 expands EventHandler
s into callbacks which let you both take and return arguments. Callbacks are a Copy
version of Box<dyn FnMut(Args) -> Ret>
built specifically for UI in Rust
#[component]
fn DoubleButton(double: Callback<u32, u32>) -> Element {
let mut count = use_signal(|| 1);
rsx! {
button {
// Callbacks let you easily inject custom logic into your components
onclick: move |_| count.set(double(count())),
"{count}"
}
}
}
Improved warnings
Dioxus 0.6 also expands the warning system to include hints for several problematic behaviors. Dioxus now warns if components are called as functions, state is passed up the component tree, or a component rerun is triggered while rendering.
Improved Inline Documentation
We also improved the inline documentation throughout the dioxus crates. Many common items now include in depth examples, explanations, and help for common errors. For comparison, here is the documentation in 0.5 and 0.6 for oninput:
and use_memo:
Bug fixes
Dioxus 0.6 also includes a plethora of bug fixes and consistency tweaks. Over 200 issues closed with 100 bugs fixed
Call for Testing
Testing the alpha release and opening issues for any bugs you run into is a great way to contribute back to dioxus!
Feel free to hop into the discord to give feedback and/or chat about the new changes.
Full Change Log
- fix the relative paths issue in the fullstack crates.io build by @ealmloff in #2248
- Use
tracing::warn!
instead oferror!
when assets not being preloaded by @photino in #2251 - Use
tracing::warn!
instead oferror!
when the dioxus CLI is not used by @photino in #2250 - Fix: CLI Logging by @DogeDark in #2254
- Bump h2 from 0.3.25 to 0.3.26 by @dependabot in #2253
- docs: ✏️ typo -> unnecessary need to in global_context.rs by @Tahinli in #2268
- Fix features not passed from dx bundle to cargo by @apuddy in #2271
- Fix volatile attributes by @ealmloff in #2278
- Poll tasks in the same order they are queued by @ealmloff in #2273
- Fix the assets head path by @ealmloff in #2267
- Fix empty for loop, if statements and children by @ealmloff in #2275
- Autofmt nested rsx using syn::Visitor by @jkelleyrtp in #2279
- Fix: autofmt shouldn't eat keys by @jkelleyrtp in #2280
- Fix event handler drops by @matthunz in #2288
- fix: Update
use_hook
docs by @marc2332 in #2296 - Fix: CLI Compilation Spam by @DogeDark in #2300
- fix: Update
use_resource
docs by @marc2332 in #2303 - fix path of set_server_url by @chungwong in #2314
- Fix flakey windows tests by @ealmloff in #2332
- chore: fix some typos in comments by @alongdate in #2340
- Bump JamesIves/github-pages-deploy-action from 4.5.0 to 4.6.0 by @dependabot in #2355
- Revision: CLI Help Docs by @DogeDark in #2349
- Bump rustls from 0.21.10 to 0.21.11 by @dependabot in #2348
- enables ability to turn off hot reloading by @alexanderjophus in #2351
- Create use_muda_event_handler hook by @ealmloff in #2367
- translate: update chinese README.md by @JryChn in #2364
- Fix desktop drag events that don't have associated files by @ealmloff in #2358
- Fix out of order fields in route definitions by @ealmloff in #2356
- Fix reclaim element when hot reloading by @ealmloff in #2361
- Extend the subscriber list instead of overriding it; fixes subscribers added in mark_dirty by @ealmloff in #2319
- Warnings for signal writes that may cause infinite loops by @ealmloff in #2277
- Remove unused once-cell in memo by @ealmloff in #2311
- Fix calling server functions on desktop by @ealmloff in #2357
- Implement hash fragments in the router by @ealmloff in #2320
- impl HasFileData for FormData by @rogusdev in #2346
- Only compress web assets in the CLI by @ealmloff in #2329
- Fix event handler memory leak by @ealmloff in #2298
- Fix memorization for the fragment component by @ealmloff in #2360
- Restore set compare hook by @ealmloff in #2287
- Refactor and fix eval channels by @ealmloff in #2302
- Fix: flaky CI by correcting autofmt to match proper spacing by @jkelleyrtp in #2369
- Fix desktop effect race condition by @ealmloff in #2313
- cli: small fixes and logging by @Niedzwiedzw in #2377
- Improve the base_path story by @pyrrho in #2381
- Fix effects triggered from async tasks; improve work scheduling docs by @ealmloff in #2370
- Make use_server_future accept FnMut by @ealmloff in #2387
- Added
dx create
options to skip user interaction by @Andrew15-5 in #1872 - feat(cli): init cmd can now skip user interaction by @Andrew15-5 in #2412
- chore(cli): optimized args handling for init & new by @Andrew15-5 in #2418
- Fix default launcher for web targets by @samtay in #2431
- Bump JamesIves/github-pages-deploy-action from 4.6.0 to 4.6.1 by @dependabot in #2432
- Add access to the Element attributes related to scrolling by @ASR-ASU in #2338
- Create a Static Site Generation platform; Deduplicate hot reloading code by @ealmloff in #2226
- Autocomplete rsx by @ealmloff in #2421
- Improved fullstack reload_upon_connect timeout by @luveti in #2436
- The value returned by get_scroll_size method is invalid by @ASR-ASU in #2445
- Fix chinese README image url by @panglars in #2449
- Bump korthout/backport-action from 2 to 3 by @dependabot in #2455
- Make use of
#[doc]
field attributes inProps
derive macro by @MrGVSV in #2456 - Set up example scraping for docs.rs by @ealmloff in #2450
- fix: Avoid cloning a provided context unnecessarily by @marc2332 in #2458
- Replace
RwLock::try_read
withRwLock::read
inSyncStorage
by @ribelo in #2463 - Switch from an absolute ::dioxus to the relative dioxus_core by @pyrrho in #2465
- Remove unused dependency from core-macro by @airblast-dev in #2466
- Remove value attribute instead of resetting it by @ealmloff in #2480
- Fix memo and resource line info by @ealmloff in #2443
- Fix routers without an index route by @ealmloff in #2477
- Fix event bubbling inside templates after a hot template reload by @ealmloff in #2484
- Update openid example by @samtay in #2474
- Improve inline docs by @ealmloff in #2460
- Change ToRouteSegments to borrow self by @ealmloff in #2283
- Fix recursive copy while bundling by @ealmloff in #2419
- Detect components called as functions by @ealmloff in #2461
- switch from slab to slotmap for tasks to fix the ABA problem by @ealmloff in #2488
- Feat: Progress Bar vs Println Mechanism by @DogeDark in #2489
- fix: Add missing name attribute for by @ilaborie in #2494
- Add Popover API by @nayo0513 in #2498
- Create closure type; allow async event handlers in props; allow short hand event handlers by @ealmloff in #2437
- Ignore
#[props(into)]
on Strings by @ealmloff in #2501 - Improve server eval error message by @ealmloff in #2502
- Integrate wasm-opt into the CLI by @ealmloff in #2434
- add file size to FileEngine by @rogusdev in #2323
- Bump braces from 3.0.2 to 3.0.3 in /packages/extension by @dependabot in #2503
- Fix hydration of empty text nodes by @ealmloff in #2505
- Add CI step to test packages with debug assertions off by @ealmloff in #2507
- Improve bug_report by @WilliamRagstad in #2532
- Update
dioxus_desktop::Config
to also allow for asynchronous custom protocol handlers by @d3rpp in #2535 - Assert that launch never returns for better compiler errors by @ealmloff in #2517
- Fix raw attribute names by @ealmloff in #2520
- Document props and component macro by @ealmloff in #2522
- Simplify dioxus-config-macro by @ealmloff in #2514
- Remove implicit optional dependency features by @ealmloff in #2512
- Convert closures into Option automatcially by @ealmloff in #2538
- nonreactive examples for hooks were not compilable as written by @rogusdev in #2337
- Make it easier to provide context to fullstack by @ealmloff in #2515
- Deduplicate reactive scope updates/Reset subscriptions on reruns/fix use memo double update by @ealmloff in #2506
- add aria-current to link by @uzytkownik in #2540
- Revision: Change Default Fullstack IP by @DogeDark in #2543
- Add missing packages in flake.nix by @uzytkownik in #2547
- Fix hot-reloading on Windows by @matthunz in #2544
- Update the examples link on the README by @hardBSDk in #2552
- Chore: move todo!() to unimplemented!() by @jkelleyrtp in #2558
- Add Section To CLI
README.md
Aboutcli-dev
Profile by @DogeDark in #2560 - Forward cli serve settings and make it easier to provide platform config to fullstack by @ealmloff in #2521
- Suspense boundaries/out of order streaming/anyhow like error handling by @ealmloff in #2365
- edit settings.json to disable format on save for the repo by @jkelleyrtp in #2572
- Switch to using refs instead of owned for autofmt write block out by @jkelleyrtp in #2573
- Switch to comments as placeholder nodes by @ealmloff in #2579
- Return error when unable to parse request uri by @ealmloff in #2578
- cut out a number of changes from the hr PR by @jkelleyrtp in #2580
- Use Manganis Linker System by @DogeDark in #2561
- Feat: CLI Settings by @DogeDark in #2424
- Partially Fix Hotreload by @DogeDark in #2557
- Remove deprecated macros: inline_props, format_args_f!, render! by @jkelleyrtp in #2574
- Fix fullstack desktop launch by @luveti in #2581
- Expand component definition before errors to fix component autocomplete from other modules by @ealmloff in #2609
- fix (desktop): hide window until the first render by @imgurbot12 in #2614
- fix (desktop): hide menu when window decorations are disabled by @imgurbot12 in #2613
- Fix context type in static generation crate by @ealmloff in #2607
- Add a playwright test that checks static generation by @ealmloff in #2608
- Fix empty web history prefixes by @ealmloff in #2621
- Bump JamesIves/github-pages-deploy-action from 4.6.1 to 4.6.3 by @dependabot in #2605
- feat (desktop): upgrade from wry 37 to 41 by @imgurbot12 in #2618
- switch to a Document trait and introduce Script/Head/Style/Meta components by @ealmloff in #2635
- Hotreloading of
for/if/body
, formatted strings, literals, component props, nested rsx, light CLI rewrite, cli TUI by @jkelleyrtp in #2258 - Improve warnings when trying to update outside of pending suspense boundaries on the server by @ealmloff in #2575
- Bump gix-path from 0.10.8 to 0.10.9 by @dependabot in #2640
- Handle deserialize errors without panic by @Septimus in #2664
- Bump openssl from 0.10.64 to 0.10.66 by @dependabot in #2673
- Fix deriving props with a where clause and an owner by @ealmloff in #2674
- Fix some CI (windows + nasm, core-macro error) by @jkelleyrtp in #2676
- Splash Screens by @DogeDark in #2657
- Re-Export Manganis & Update Examples by @DogeDark in #2625
- Fix generation race condition with sync storage by @ealmloff in #2638
- Remove Dioxus CLI NASM dependency #2666 by @opensource-inemar-net in #2682
- Make VirtualDom constructor take an
impl Fn()
instead of a function pointer by @oskardotglobal in #2583 - Allow no trailing comma after attributes by @ealmloff in #2651
- Expand to a partial Component if a shorthand attribute starts with a capital letter by @ealmloff in #2652
- Fix cli readme local installation instructions by @ealmloff in #2671
- Disable browser shortcut keys on windows by @ealmloff in #2654
- CLI: Add a signal handler to reset the cursor on interrupt by @FragrantArmpit in #2603
- Fix: CLI Drain Logs by @DogeDark in #2686
- Fix: Windows Hot Reload by @DogeDark in #2687
- Web Eval: Use JSON Compatible Serializer by @DogeDark in #2592
- Fix: File Watcher Ignore List by @DogeDark in #2689
- Fix rsx autocomplete and diagnostics in the root; provide better completions after attributes are finished by @ealmloff in #2656
- Parse raw elements, attributes, and web components in rsx by @ealmloff in #2655
- CI: re-reorder free disk space action to clear free up space earlier by @jkelleyrtp in #2690
- Fix spread props diffing by @ealmloff in #2679
- Improve error message when the CLI and dioxus versions don't match by @ealmloff in #2683
- fix most typos, add crate-ci/typos to CI by @LeoDog896 in #2653
- Better
expect
error messages by @matthunz in #2629 - Fix playwright tests by @ealmloff in #2695
- feat(cli): added git commit hash to version output by @Andrew15-5 in #2696
- Unify the warning system by @ealmloff in #2649
- Add a deprecation warning for the resource option in dioxus.toml by @ealmloff in #2642
- Make dioxus-cli a binary - not a library by @ealmloff in #2698
- fix formatting and merging if chains in attributes by @ealmloff in #2697
- Make the web config optional in dioxus.toml by @ealmloff in #2700
- Fix
debug_assertions
incore::tasks
by @matthunz in #2703 - CLI: Toasts & Tweaks by @DogeDark in #2702
- Use head elements and new manganis syntax in examples by @ealmloff in #2688
- Parse redirects in the same order they appear in by @ealmloff in #2650
- Fix #2612: adjust readable trait to allow try_peek by @jkelleyrtp in #2714
- Feat:
always_on_top
CLI Setting by @DogeDark in #2715 - Fix #1188: enable dangerous_inner_html for svgs by @jkelleyrtp in #2717
- TUI tweaks by @matthunz in #2685
- Fix #2378: CLI MSRV and add MSRV to CI by @jkelleyrtp in #2716
- This fixes issue #2723 by @opensource-inemar-net in #2724
- fix issue 1586 by @i123iu in #2725
- desktop app saves window position fix by @i123iu in #2730
- implement HasMouseData for WheelEvent by @i123iu in #2728
- Fix WSL Hot Reload by @DogeDark in #2721
- fix issue 1586 followup by @i123iu in #2733
- Follow-up for error messages in core by @matthunz in #2719
- speed up incremental cli builds by making wasm-opt optional by @jkelleyrtp in #2720
- Fix #2309: rfd doesn't need async-std by @jkelleyrtp in #2712
- Fix: Enable/Disable Hot Reload by @DogeDark in #2737
- Add short
p
option forpackage
to matchcargo
by @matthunz in #2738 - Pass
-package
to Cargo #1547 by @matthunz in #2740 - Switch to a pool of dynamic values for hot reloading by @ealmloff in #2705
- Fix component names when they are re-exported by @ealmloff in #2744
- Fix diffing Option by @ealmloff in #2746
- Don't print the asset path on desktop by @ealmloff in #2748
- Fix list diffing with root dynamic nodes by @ealmloff in #2749
- Fix hot reloading spreads by @ealmloff in #2750
- Workspace support for
dx fmt
by @matthunz in #2745 - Fix: #2604, Fix: #2240, Fix: #2341, Fix #1355 - Better error handling and and spaces handling in autofmt by @jkelleyrtp in #2736
- Fix: #1964: Use the correct to-static impl for sending escaped strings via hotreload by @jkelleyrtp in #2753
- Fix 2265: close tui on success, custom tui subscriber by @jkelleyrtp in #2734
- Refactor
WebEventExt
by @matthunz in #2707 - Fix the base path in the CLI by @ealmloff in #2756
- Feat: Auto Default Into by @DogeDark in #2757
- Pre-release 0.6.0-alpha.0 by @jkelleyrtp in #2755
- release: 0.6.0-alpha.1 (improve docs.rs for fullstack, dioxus) by @jkelleyrtp in #2760
New Contributors!
- @photino made their first contribution in #2251
- @apuddy made their first contribution in #2271
- @chungwong made their first contribution in #2314
- @alongdate made their first contribution in #2340
- @rogusdev made their first contribution in #2346
- @pyrrho made their first contribution in #2381
- @samtay made their first contribution in #2431
- @ASR-ASU made their first contribution in #2338
- @luveti made their first contribution in #2436
- @panglars made their first contribution in #2449
- @MrGVSV made their first contribution in #2456
- @ribelo made their first contribution in #2463
- @airblast-dev made their first contribution in #2466
- @ilaborie made their first contribution in #2494
- @nayo0513 made their first contribution in #2498
- @WilliamRagstad made their first contribution in #2532
- @d3rpp made their first contribution in #2535
- @uzytkownik made their first contribution in #2540
- @hardBSDk made their first contribution in #2552
- @imgurbot12 made their first contribution in #2614
- @Septimus made their first contribution in #2664
- @opensource-inemar-net made their first contribution in #2682
- @oskardotglobal made their first contribution in #2583
- @FragrantArmpit made their first contribution in #2603
- @LeoDog896 made their first contribution in #2653
- @i123iu made their first contribution in #2725
Full Diff: v0.5.1...v0.6.0-alpha.1