Releases: DioxusLabs/dioxus
v0.4.2
What's Changed
- Reject all external routes when parsing a route by @ealmloff in #1272
- Fix navigator push/replace route by @ealmloff in #1274
- Deduplicate route history by @ealmloff in #1273
- Update scroll history lazily when you leave a page by @ealmloff in #1275
- Release new versions (0.4.1) by @jkelleyrtp in #1276
- fixed "http_equiv" in meta to generate "http-equiv" instead of "http_… by @ChrisCA in #1277
- Fix Fullstack docs building by @ealmloff in #1284
- Make server function features flexible by @ealmloff in #1285
- doc: fix typo by @eventualbuddha in #1287
- docs(cli): fix typo by @eventualbuddha in #1294
- build(web): fix
default-features
warning by @eventualbuddha in #1296 - Minor Proxy Improvements by @eventualbuddha in #1289
- docs(hooks): fix typos by @eventualbuddha in #1299
- refactor(cli): move
check
module alongside others by @eventualbuddha in #1304 - docs(cli): update subcommand comments by @eventualbuddha in #1303
- chore(cli): remove unused module by @eventualbuddha in #1302
- fix(cli): prevent "zip slip" vulnerability in tool extract by @eventualbuddha in #1305
- incorrect word spelling by @dylanblokhuis in #1308
- chore(cli): remove unused function by @eventualbuddha in #1301
- refactor(cli): use more semantic
Instant::elapsed
by @eventualbuddha in #1307 - fix: readme awesome link by @HashCookie in #1320
- Set response headers from response, not request, parts by @gmorenz in #1328
- docs: add Japanese README by @eltociear in #1329
- Make launch functions pub by @CodedNil in #1288
- Separate Parent and Child Component Lifetimes by @ealmloff in #1332
- Fix the login form example by @ealmloff in #1327
- Complete Signals implementation by @ealmloff in #1300
- Update tailwind examples to work with multi-page apps by @swpecht in #1339
- Use
--profile
to identify cargo build artifact if present for dx cli web builds by @swpecht in #1344 - Add 'with' and 'with_mut' to 'use_shared_state' by @DanielAlbl in #1353
- Publish CLI binaries for cargo-binstall by @esimkowitz in #1358
- Fix the context API in lists by @ealmloff in #1351
- Fix leak in core because of bump allocated Vec by @ealmloff in #1364
- Update README.md to use 0.4 version of
Guide
instead of 0.3 by @Dillon-Roller in #1370 - DOC: Add note about form prevent_default behavior. by @vgobbo in #1343
- CLI: Behavior when web.https.mkcert is not specified. by @vgobbo in #1342
- FileEngine: expose native file types on different platforms by @wooden-worm in #1258
- deps: Update keyboard-types to 0.7. by @waywardmonkeys in #1378
- Update ZH_CN.md to use 0.4 version of guide by @HashCookie in #1388
- Constrain Props lifetime to parent, not child scope lifetime by @ealmloff in #1345
New Contributors
- @ChrisCA made their first contribution in #1277
- @dylanblokhuis made their first contribution in #1308
- @HashCookie made their first contribution in #1320
- @gmorenz made their first contribution in #1328
- @eltociear made their first contribution in #1329
- @CodedNil made their first contribution in #1288
- @swpecht made their first contribution in #1339
- @Dillon-Roller made their first contribution in #1370
- @vgobbo made their first contribution in #1343
- @wooden-worm made their first contribution in #1258
- @waywardmonkeys made their first contribution in #1378
Full Changelog: v0.4.0...v0.4.2
v0.4.1
What's Changed
- docs(cli): fix typo by @eventualbuddha in #1294
- refactor(cli): move
check
module alongside others by @eventualbuddha in #1304 - docs(cli): update subcommand comments by @eventualbuddha in #1303
- chore(cli): remove unused module by @eventualbuddha in #1302
- fix(cli): prevent "zip slip" vulnerability in tool extract by @eventualbuddha in #1305
- incorrect word spelling by @dylanblokhuis in #1308
- chore(cli): remove unused function by @eventualbuddha in #1301
- refactor(cli): use more semantic
Instant::elapsed
by @eventualbuddha in #1307 - Use
--profile
to identify cargo build artifact if present for dx cli web builds by @swpecht in #1344 - Publish CLI binaries for cargo-binstall by @esimkowitz in #1358
- CLI: Behavior when web.https.mkcert is not specified. by @vgobbo in #1342
- Fix cli compile error due to tauri bundler adding fields by @fanyang89 in #1416
- Improve CLI docs by @tigerros in #1404
- fix: Add the --locked param to every cli installation command by @marc2332 in #1427
- Bump the dioxus-cli to 0.4.1 by @ealmloff in #1424
v0.4.0
Dioxus 0.4 Github
The Dioxus 0.4 release includes 6 new crates, a ton of new features and a plethora of bug fixes!
Highlights:
- Rewritten Type safe Router
- Fullstack cross-platform meta framework
- Suspense
- CLI Linting
- CLI Bundling
- Rewritten Documentation
- Cross platform system API wrappers: Dioxus STD
Router
The router has been revamped for the 0.4 release. The router now uses an enum to define routes. If you use this enum to link to a page, the compiler will insure you never link to a page that doesn’t exist. The new router also includes Nesting, Layout, and sitemap support:
use dioxus::prelude::*;
use dioxus_router::prelude::*;
#[derive(Routable, Clone)]
enum Route {
#[route("/")]
Home {},
#[route("/blog")]
Blog {},
}
fn App(cx: Scope) -> Element {
render! {
Router::<Route> {}
}
}
#[inline_props]
fn Home(cx: Scope) -> Element {
render! {
Link {
to: Route::Blog {},
"Go to the blog"
}
h1 { "Welcome to the Dioxus Blog!" }
}
}
#[inline_props]
fn Blog(cx: Scope) -> Element {
render! {
Link {
to: Route::Home {},
"Go to the home page"
}
h1 { "Blog" }
}
}
Huge shoutout to @TeFiLeDo for creating many different prototypes and tests for the new router!
Fullstack
The 0.4 release introduces the Fullstack crate. The fullstack crate contains adapters for communicating with your
Fullstack Rendering
The fullstack crate makes it dead simple to create a server side rendered hydrated app with fullstack typesafety. The fullstack crate lets you render your page on the server on every request (or incrementally) and then hydrate it on the client.
use dioxus::prelude::*;
use dioxus_fullstack::prelude::*;
fn main() {
LaunchBuilder::new(app).launch();
}
fn app(cx: Scope) -> Element {
let mut count = use_state(cx, || 0);
render! {
h1 { "High-Five counter: {count}" }
button { onclick: move |_| count += 1, "Up high!" }
button { onclick: move |_| count -= 1, "Down low!" }
}
}
Fullstack communication
In addition to fullstack rendering, the new fullstack create allows you to communicate with your server effortlessly. You can annotate a function with #[server]
to make the code inside the function only run on the server. This makes it easy to build a backend for your web or desktop application!
use dioxus::prelude::*;
use dioxus_fullstack::prelude::*;
fn main() {
LaunchBuilder::new(app).launch();
}
fn app(cx: Scope) -> Element {
let mut count = use_state(cx, || 0);
render! {
h1 { "High-Five counter: {count}" }
button { onclick: move |_| count += 1, "Up high!" }
button { onclick: move |_| count -= 1, "Down low!" }
button {
onclick: move |_| {
to_owned![count];
async move {
let double = double(*count).await.unwrap();
count.set(double);
}
}
}
}
}
#[server]
async fn double(number: usize) -> Result<usize, ServerFnError> {
// This will *only* run on the server
Ok(number * 2)
}
Suspense
0.4 adds the long awaited suspense feature. This allows you to wait for a future on the server and then send the result to the client. You can combine suspense with server functions to wait for some code on your server to finish running before rendering a component:
use dioxus::prelude::*;
use dioxus_fullstack::prelude::*;
fn main() {
LaunchBuilder::new(app).launch();
}
fn app(cx: Scope) -> Element {
let mut server_data = use_server_future(cx, || get_server_data())?;
render! {
div {
"{server_data:?}"
}
}
}
#[server]
async fn get_server_data() -> Result<usize, ServerFnError> {
Ok(42)
}
CLI Improvements
The Dioxus CLI has moved into the dioxus main repo
The Dioxus CLI is now called dx
instead of dioxus
. The 0.4 release of the Dioxus CLI added three main features:
Dioxus Check
@eventualbuddha has done a fantastic job creating a new Dioxus check command to lint your Dioxus code for errors! It will warn you if your code violates the rules of hooks
dx check
Dioxus Bundle
The Dioxus CLI can now create installers for MacOs and Windows powered by tauri-bundle!
dioxus bundle
Desktop Hot Reload
In Dioxus 0.4, rsx hot reloading has moved from the hot reload macro to the CLI for desktop, liveview, fullstack, and TUI applications. Now every platform can use the CLI to start hot reloading:
dioxus serve --platform desktop --hot-reload
Mobile
Dioxus now has improved mobile support with a getting started guide and a mobile example!
Documentation
The documentation has been revamped for the 0.4 release. We now have a short getting started guide that teaches you how to build a hackernews clone in Dioxus.
The new documentation site takes full advantage of the fullstack crate to prerender the pages.
While working on the new docsite we also created two new crates:
- Dioxus Mdbook makes it easy to use markdown into your Dioxus components and use Dioxus components in your markdown
- Dioxus Search makes it easy to create instant search indexes for your Dioxus page's. It integrates with the Dioxus router's new site map feature to automatically detect searchable pages
Together these crates allow us to make our documentation fully interactive and instantly searchable. The new documentation site contains live code snippets of different components as you walk through the guide.
Dioxus STD
One of the biggest problems with cross platform development in rust today is finding ergonomic ways to interact with system APIs. @doge and @marc have created a new Dioxus std create that makes it easy to interact with a variety of system APIs in Dioxus across all platforms. It contains helpers for Geolocation, clipboard access, notifications, color schemes, translation, and more!
Async Eval
@doge has made the use_eval hook significantly more powerful for the 0.4 release of Dioxus. You can now send messages to and from Javascript asynchronously. This feature makes it possible to listen for Javascript events that Dioxus doesn’t officially support (for example the intersection observer API).
Dioxus HTML
The 0.4 release introduces file upload support for the dioxus-html crate. This makes it easy to upload files to you desktop, liveview, or web application.
This release also introduces a new onmounted event that provides access to some common node APIs like focusing an element or getting the size of an element in a cross platform way.
Rink and Blitz-core
Dioxus' TUI renderer Rink and WGPU renderer Blitz can now be used without Dioxus. This makes it possible to render your own html into either of these renderers or use these renderers in your own framework. To get started, see the Blitz and Rink framework-less examples.
Community
Office Hours
Dioxus now holds weekly office hours in the discord! If you are interested in the project, need help with your projects, or want to get started contributing, you should come to our weekly office hours!
The office hours happen every Friday at 9:00 AM (PDT) in the Dioxus discord server
Recordings of office hours are available on the Dioxus youtube channel
New contributors
There have been almost 50 new contributors since the 0.3 release!
@mirkootter, @davidpdrsn, @mwcz, @askreet, @marcerhans, @ndarilek, @arniu, @pickfire, @arqalite, @ProfXwing, @Icekey, @willothy, @rtwfroody, @attilio, @stephenandary, @Rigellute, @onweru, @Byron, @nicoburns, @serzhiio, @indiv0, @azriel91, @elliotwaite, @nmlt, @nicholastmosher, @TimothyStiles, @jpearnshaw, @jmsfltchr, @striezel, @echochamber, @xinglixing, @sean, @torsteingrindvik, @vanhouc, @terhechte, @traxys, @Mouradost, @DianQK, @eventualbuddha, @leahiel, @kaid, @frisoft, @Niedzwiedzw
Conclusion
For more information on the 0.4 release and all the new features that have been introduced, read the blogpost
Full Changelog: v0.3.2...v0.4.0
v0.3.2
Dioxus 0.3 is bringing a lot of fantastic new features:
- Massive performance improvements
- Hot reloading for web and desktop
- Autoformatting for RSX via dioxus fmt
- New LiveView renderer
- Input widgets for TUI
- Lua plugin system for CLI and overhaul of CLI
- Multi window desktop apps and direct access to Tao/Wry
- General improvements to RSX (if chains, for loops, boolean attributes, any values)
- Rusty event types with support for complex techniques like file uploading
- Skia renderer and WGPU renderer
- Chinese and Portuguese translations
- A new landing page
For more details about each of these new improvements see the release blog post
v0.2.4
Releasing Diouxs v0.2.4
This update is just a minor bump to Dioxus. A ton of bugs were fixed, and a few new features were added.
Notably
- Option in props are now optional by default
- Active_class for Links
- Improve rsx! errors
- Fix some bugs in hydration
- Introduce a very young version of Liveview
- Introduce a very young version of Dioxus Native (just the core bits)
- use_eval for running JS
A bunch of bugs were fixed too!
Overall, this release will improve the stability, performance, and usability of Dioxus without any major breaking changes.
What's Changed
- Added active class to router link by @maccesch in #294
- active_class prop for Router by @maccesch in #309
- fix: Filter prevent default for buttons in Dioxus Desktop by @jkelleyrtp in #310
- Remove release_max_level features from several Cargo.toml log dependencies by @naturalethic in #314
- Update setup.md by @imbolc in #323
- Improve
rsx!
errors by @overlisted in #322 - Option<...> props are optional by default. by @maccesch in #315
- Capture correct radio button value in a form input event by @naturalethic in #320
- fix: setnode method for rehydration code by @jkelleyrtp in #316
#[inline_props]
generics by @overlisted in #324- tui bugfixes and text modifier elements by @Demonthos in #302
- fix: instantly resolving futures should not use popping by @jkelleyrtp in #330
- Convert all logs to trace by @naturalethic in #334
- Fix form value collecting from form element instead of input element by @naturalethic in #333
- Fixed Docs Problem by @mrxiaozhuox in #336
- Minor improvements to the guide by @kdwarn in #335
- fix: diff_lazynodes bug adding children by @Demonthos in #331
- Eval stuff by @overlisted in #318
- Include optional public-url flag in build instruction within getting … by @TimboTambo in #343
- Fix typo in docs for NodeFactory.bump by @autarch in #350
- fix: inline props should look for attributes by @jkelleyrtp in #347
- Update mobile.md by @erlend-sh in #349
- Fixed example by @mrxiaozhuox in #356
- Fixed Document by @mrxiaozhuox in #357
- feat: allow customizing the index and head by @jkelleyrtp in #353
- Fix query parsing by @MiriChan in #358
- feat: Add a use_state equivalent for Fermi by @jkelleyrtp in #341
- Removed alerts when right click is disabled. by @blemelin in #363
- Add PartialEq to events::KeyCode by @freopen in #365
- add benchmark, headless mode, and shutdown context to tui by @Demonthos in #362
- Liveview Axum Integration + Example updates by @WIGGLES-dev in #366
- fix: unmarking component as dirty in silent write by @koptan in #378
- fix: export useeffect in hooks module by @koptan in #379
- Remove
cli
docs by @mrxiaozhuox in #380 - FEAT: Allow starting live view apps with props by @WIGGLES-dev in #377
- Fix cfg conditions for wasm by @DusterTheFirst in #382
- Convert web_sys Events to html Data by @oovm in #240
- change with_ctrl_c_quit to without_ctrl_c_quit for tui config by @Demonthos in #388
- Tui Lazy Attributes and Layout by @Demonthos in #329
New Contributors
- @maccesch made their first contribution in #294
- @naturalethic made their first contribution in #314
- @imbolc made their first contribution in #323
- @Demonthos made their first contribution in #302
- @kdwarn made their first contribution in #335
- @TimboTambo made their first contribution in #343
- @erlend-sh made their first contribution in #349
- @MiriChan made their first contribution in #358
- @freopen made their first contribution in #365
- @WIGGLES-dev made their first contribution in #366
- @koptan made their first contribution in #378
- @DusterTheFirst made their first contribution in #382
Full Changelog: v0.2.0...v0.2.4
v0.2.0
Dioxus v0.2 Release: TUI, Router, Fermi, and Tooling
March 9, 2022
Thanks to these amazing folks for their financial support on OpenCollective:
Thanks to these amazing folks for their code contributions:
Just over two months in, and we already a ton of awesome changes to Dioxus!
Dioxus is a recently-released library for building interactive user interfaces (GUI) with Rust. It is built around a Virtual DOM, making it portable for the web, desktop, server, mobile, and more. Dioxus looks and feels just like React, so if you know React, then you'll feel right at home.
fn app(cx: Scope) -> Element {
let mut count = use_state(&cx, || 0);
cx.render(rsx! {
h1 { "Count: {count}" }
button { onclick: move |_| count += 1, "+" }
button { onclick: move |_| count -= 1, "-" }
})
}
What's new?
A ton of stuff happened in this release; 550+ commits, 23 contributors, 2 minor releases, and 6 backers on Open Collective.
Some of the major new features include:
- We now can render into the terminal, similar to Ink.JS - a huge thanks to @Demonthos
- We have a new router in the spirit of React-Router @autarch
- We now have Fermi for global state management in the spirit of Recoil.JS
- Our desktop platform got major upgrades, getting closer to parity with Electron @mrxiaozhuox
- Our CLI tools now support HTML-to-RSX translation for converting 3rd party HTML into Dioxus @mrxiaozhuox
- Dioxus-Web is sped up by 2.5x with JS-based DOM manipulation (3x faster than React)
We also fixed and improved a bunch of stuff - check out the full list down below.
A New Renderer: Your terminal!
When Dioxus was initially released, we had very simple support for logging Dioxus elements out as TUI elements. In the past month or so, @Demonthos really stepped up and made the new crate a reality.
New Router
We totally revamped the router, switching away from the old yew-router approach to the more familiar React-Router. It's less type-safe but provides more flexibility and support for beautiful URLs.
Apps with routers are really simple now. It's easy to compose the "Router", a "Route", and "Links" to define how your app is laid out:
fn app(cx: Scope) -> Element {
cx.render(rsx! {
Router {
onchange: move |_| log::info!("Route changed!"),
ul {
Link { to: "/", li { "Go home!" } }
Link { to: "users", li { "List all users" } }
Link { to: "blog", li { "Blog posts" } }
}
Route { to: "/", "Home" }
Route { to: "/users", "User list" }
Route { to: "/users/:name", User {} }
Route { to: "/blog", "Blog list" }
Route { to: "/blog/:post", BlogPost {} }
Route { to: "", "Err 404 Route Not Found" }
}
})
}
We're also using hooks to parse the URL parameters and segments so you can interact with the router from anywhere deeply nested in your app.
#[derive(Deserialize)]
struct Query { name: String }
fn BlogPost(cx: Scope) -> Element {
let post = use_route(&cx).segment("post")?;
let query = use_route(&cx).query::<Query>()?;
cx.render(rsx!{
"Viewing post {post}"
"Name selected: {query}"
})
}
Give a big thanks to @autarch for putting in all the hard work to make this new router a reality.
The Router guide is available here - thanks to @dogedark.
Fermi for Global State Management
Managing state in your app can be challenging. Building global state management solutions can be even more challenging. For the first big attempt at building a global state management solution for Dioxus, we chose to keep it simple and follow in the footsteps of the Recoil.JS project.
Fermi uses the concept of "Atoms" for global state. These individual values can be get/set from anywhere in your app. Using state with Fermi is basically as simple as use_state
.
// Create a single value in an "Atom"
static TITLE: Atom<&str> = |_| "Hello";
// Read the value from anywhere in the app, subscribing to any changes
fn app(cx: Scope) -> Element {
let title = use_read(&cx, TITLE);
cx.render(rsx!{
h1 { "{title}" }
Child {}
})
}
// Set the value from anywhere in the app
fn Child(cx: Scope) -> Element {
let set_title = use_set(&cx, TITLE);
cx.render(rsx!{
button {
onclick: move |_| set_title("goodbye"),
"Say goodbye"
}
})
}
Inline Props Macro
For internal components, explicitly declaring props structs can become tedious. That's why we've built the new inline_props
macro. This macro lets you inline your props definition right into your component function arguments.
Simply add the inline_props
macro to your component:
#[inline_props]
fn Child<'a>(
cx: Scope,
name: String,
age: String,
onclick: EventHandler<'a, ClickEvent>
) -> Element {
cx.render(rsx!{
button {
"Hello, {name}"
"You are {age} years old"
onclick: move |evt| onclick.call(evt)
}
})
}
You won't be able to document each field or attach attributes so you should refrain from using it in libraries.
Props optional fields
Sometimes you don't want to specify every value in a component's props, since there might a lot. That's why the Props
macro now supports optional fields. You can use a combination of default
, strip_option
, and optional
to tune the exact behavior of properties fields.
#[derive(Props, PartialEq)]
struct ChildProps {
#[props(default = "client")]
name: String,
#[props(default)]
age: Option<u32>,
#[props(optional)]
age: Option<u32>,
}
// then to use the accompanying component
rsx!{
Child {
name: "asd",
}
}
Dioxus Web Speed Boost
We've changed how DOM patching works in Dioxus-Web; now, all of the DOM manipulation code is written in TypeScript and shared between our web, desktop, and mobile runtimes.
On an M1-max, the "create-rows" operation used to take 45ms. Now, it takes a mere 17ms - 3x faster than React. We expect an upcoming optimization to bring this number as low as 3ms.
Under the hood, we have a new string interning engine to cache commonly used tags and values on the Rust <-> JS boundary, resulting in significant performance improvements.
Overall, Dioxus apps are even more snappy than before.
Dioxus Desktop Window Context
A very welcome change, thanks AGAIN to @mrxiaozhuox is support for imperatively controlling the desktop window from your Dioxus code.
A bunch of new methods were added:
- Minimize and maximize window
- Close window
- Focus window
- Enable devtools on the fly
And more!
In addition, Dioxus Desktop now autoresolves asset locations, so you can easily add local images, JS, CSS, and then bundle it into an .app without hassle.
You can now build entirely borderless desktop apps:
CLI Tool
Thanks to the amazing work by @mrxiaozhuox, our CLI tool is fixed and working better than ever. The Dioxus-CLI sports a new development server, an HTML to RSX translation engine, a cargo fmt
-style command, a configuration scheme, and much more.
Unlike its counterpart, Trunk.rs
, the dioxus-cli supports running examples and tests, making it easier to test web-based projects and showcase web-focused libraries.
Async Improvements
Working with async isn't the easiest part of Rust. To help improve things, we've upgraded async support across the board in Dioxus.
First, we upgraded the use_future
hook. It now supports dependencies, which let you regenerate a future on the fly as its computed values change. It's never been easier to add datafetching to your Rust Web Apps:
fn RenderDog(cx: Scope, breed: String) -> Element {
let dog_request = use_future(&cx, (breed,), |(breed,)| async move {
reqwest::get(format!("https://dog.ceo/api/breed/{}/images/random", breed))
.await
.unwrap()
.json::<DogApi>()
.await
});
cx.render(match dog_request.value() {
Some(Ok(url)) => rsx!{ img { url: "{url}" } },
Some(Err(url)) => rsx!{ span { "Loading dog failed" } },
None => rsx!{ "Loading dog..." }
})
}
Additionally, we added better support for coroutines. You can now start, stop, resume, and message with asynchronous tasks. The coroutine is automatically exposed to the rest of your app via the Context API. For the vast majority of apps, Coroutines can satisfy all of your state management needs:
fn App(cx: Scope) -> Element {
let sync_task = use_coroutine(&cx, |rx| async ...
v0.1.7
Bug Fixes
- tests
Commit Statistics
- 1 commit contributed to the release over the course of 2 calendar days.
- 1 commit where understood as conventional.
- 0 issues like '(#ID)' where seen in commit messages
Commit Details
view details
- Uncategorized
- tests (bd341f5)
Dioxus v0.1.0
Introducing Dioxus v0.1 ✨
Jan 3, 2022
After many months of work, we're very excited to release the first version of Dioxus!
Dioxus is a new library for building interactive user interfaces (GUI) with Rust. It is built around a Virtual DOM, making it portable for the web, desktop, server, mobile, and more.
Dioxus has the following design goals:
- Familiar: Offer a React-like mental model and API surface
- Robust: Avoid runtime bugs by moving rules and error handling into the type system
- Performant: Scale to the largest apps and the largest teams
- Productive: Comprehensive inline documentation, fast recompiles, and deeply integrated tooling
- Extensible: Reusable hooks and components that work on every platform
Dioxus is designed to be familiar for developers already comfortable with React paradigms. Our goal is to ensure a smooth transition from TypeScript/React without having to learn any major new concepts.
To give you an idea of what Dioxus looks like, here's a simple counter app:
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app)
}
fn app(cx: Scope) -> Element {
let mut count = use_state(&cx, || 0);
cx.render(rsx! {
h1 { "Count: {count}" }
button { onclick: move |_| count += 1, "+" }
button { onclick: move |_| count -= 1, "-" }
})
}
This simple counter is a complete desktop application, running at native speeds on a native thread. Dioxus automatically shuttles all events from the WebView runtime into the application code. In our app, we can interact natively with system APIs, run multi-threaded code, and do anything a regular native Rust application might do. Running cargo build --release
will compile a portable binary that looks and feels the same on Windows, macOS, and Linux. We can then use cargo-bundle
to bundle our binary into a native .app
/.exe
/.deb
.
Dioxus supports many of the same features React does including:
- Server-side-rendering, pre-rendering, and hydration
- Mobile, desktop, and web support
- Suspense, fibers, coroutines, and error handling
- Hooks, first-class state management, components
- Fragments, conditional rendering, and custom elements
However, some things are different in Dioxus:
- Automatic memoization (opt-out rather than opt-in)
- No effects - effectual code can only originate from actions or coroutines
- Suspense is implemented as hooks - not deeply ingrained within Dioxus Core
- Async code is explicit with a preference for coroutines instead
As a demo, here's our teaser example running on all our current supported platforms:
This very site is built with Dioxus, and the source code is available here.
To get started with Dioxus, check out any of the "Getting Started" guides for your platform of choice, or check out the GitHub Repository for more details.
- Getting Started with Dioxus
- Getting Started with Web
- Getting Started with Desktop
- Getting Started with Mobile
- Getting Started with SSR
Show me some examples of what can be built!
- File explorer desktop app
- WiFi scanner desktop app
- Dog CEO API Search
- TodoMVC Mobile App
- E-Commerce Liveview App
Why should I use Rust and Dioxus for frontend?
We believe that Rust's ability to write high-level and statically typed code should make it easier for frontend teams to take on even the most ambitious of projects. Rust projects can be refactored fearlessly: the powerful type system prevents an entire class of bugs at compile-time. No more cannot read property of undefined
ever again! With Rust, all errors must be accounted for at compile time. You cannot ship an app that does not — in some way — handle its errors.
Difference from TypeScript/React:
TypeScript is still fundamentally JavaScript. If you've written enough TypeScript, you might be bogged down with lots of configuration options, lack of proper support for "go-to-source," or incorrect ad-hoc typing. With Rust, strong types are built-in, saving tons of headache like cannot read property of undefined
.
By using Rust, we gain:
- Strong types for every library
- Immutability by default
- A simple and intuitive module system
- Integrated documentation (go to source actually goes to source instead of the
.d.ts
file) - Advanced pattern matching
- Clean, efficient, composable iterators
- Inline built-in unit/integration testing
- High quality error handling
- Flexible standard library and traits
- Powerful macro system
- Access to the crates.io ecosystem
Dioxus itself leverages this platform to provide the following guarantees:
- Correct use of immutable data structures
- Guaranteed handling of errors and null-values in components
- Native performance on mobile
- Direct access to system IO
And much more. Dioxus makes Rust apps just as fast to write as React apps, but affords more robustness, giving your frontend team greater confidence in making big changes in shorter timespans.
Semantically, TypeScript-React and Rust-Dioxus are very similar. In TypeScript, we would declare a simple component as:
type CardProps = {
title: string,
paragraph: string,
};
const Card: FunctionComponent<CardProps> = (props) => {
let [count, set_count] = use_state(0);
return (
<aside>
<h2>{props.title}</h2>
<p> {props.paragraph} </p>
<button onclick={() => set_count(count + 1)}> Count {count} </button>
</aside>
);
};
In Dioxus, we would define the same component in a similar fashion:
#[derive(Props, PartialEq)]
struct CardProps {
title: String,
paragraph: String
}
static Card: Component<CardProps> = |cx| {
let mut count = use_state(&cx, || 0);
cx.render(rsx!(
aside {
h2 { "{cx.props.title}" }
p { "{cx.props.paragraph}" }
button { onclick: move |_| count+=1, "Count: {count}" }
}
))
};
However, we recognize that not every project needs Rust - many are fine with JavaScript! We also acknowledge that Rust/Wasm/Dioxus does not fix "everything that is wrong with frontend development." There are always going to be new patterns, frameworks, and languages that solve these problems better than Rust and Dioxus.
As a general rule of thumb, Dioxus is for you if:
- your app will become very large
- you need to share code across many platforms
- you want a fast way to build for desktop
- you want to avoid electron or need direct access to hardware
- you're tired of JavaScript tooling
Today, to publish a Dioxus app, you don't need NPM/WebPack/Parcel/etc. Dioxus simply builds with cargo, and for web builds, Dioxus happily works with the popular trunk project.
Show me more
Here, we'll dive into some features of Dioxus and why it's so fun to use. The guide serves as a deeper and more comprehensive look at what Dioxus can do.
Building a new project is simple
To start a new project, all you need is Cargo, which comes with Rust. For a simple desktop app, all we'll need is the dioxus
crate with the appropriate desktop
feature. We start by initializing a new binary crate:
$ cargo init dioxus_example
$ cd dioxus_example
We then add a dependency on Dioxus to the Cargo.toml
file, with the "desktop" feature enabled:
[dependencies]
dioxus = { version = "*", features = ["desktop"] }
We can add our counter from above.
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app)
}
fn app(cx: Scope) -> Element {
let mut count = use_state(&cx, || 0);
cx.render(rsx! {
h1 { "Count: {count}" }
button { onclick: move |_| count += 1, "+" }
button { onclick: move |_| count -= 1, "-" }
})
}
And voilà! We can cargo run
our app
Support for JSX-style templating
Dioxus ships with a templating macro called RSX, a spin on React's JSX. RSX is very similar to regular struct syntax for Rust so it integrates well with your IDE. If used with Rust-Analyzer (not tested anywhere else) RSX supports code-folding, block selection, bracket pair colorizing, autocompletion, symbol renaming — pretty much anything you would expect from writing regular struct-style code.
rsx! {
div { "Hello world" }
button {
onclick: move |_| log::info!("button pressed"),
"Press me"
}
}
If macros aren't your style, you can always drop down to the factory API:
LazyNodes::new(|f| {
f.fragment([
f.element(div, [f.text("hello world")], [], None, None)
f.element(
button,
[f.text("Press Me")],
[on::click(move |_| log::info!("button pressed"))],
None,
None
)
])
})
The rsx!
macro generates idiomatic Rust code that uses the factory API — no different than what you'd write by hand yourself.
To make it easier to work with RSX, we've built a small VSCode extension with useful utilities. This extension provides a command that converts a selected block of HTML into RSX so you can easily reuse existing web templates.
Dioxus is perfected for the IDE
Note: all IDE-related features have only been tested with [Rust-Analyzer](https://github.com/rust-analyzer/...