update the dioxus cratesio readme, add many more examples (#5501)

* update the dioxus cratesio readme

* fix example

* fix header

* add a bunch more examples
This commit is contained in:
Jonathan Kelley authored and GitHub committed 2026-04-21 17:07:48 -07:00
1 parent 74e7d20f80
commit cd54f5953b
30 files changed
+1403 -235

No files matched your search

+117 -2
View File
@@ -579,6 +579,56 @@ name = "svg"
path = "examples/02-building-ui/svg.rs"
doc-scrape-examples = true
[[example]]
name = "counter"
path = "examples/02-building-ui/counter.rs"
doc-scrape-examples = true
[[example]]
name = "conditional_rendering"
path = "examples/02-building-ui/conditional_rendering.rs"
doc-scrape-examples = true
[[example]]
name = "lists"
path = "examples/02-building-ui/lists.rs"
doc-scrape-examples = true
[[example]]
name = "components"
path = "examples/02-building-ui/components.rs"
doc-scrape-examples = true
[[example]]
name = "children"
path = "examples/02-building-ui/children.rs"
doc-scrape-examples = true
[[example]]
name = "inputs"
path = "examples/02-building-ui/inputs.rs"
doc-scrape-examples = true
[[example]]
name = "forms"
path = "examples/02-building-ui/forms.rs"
doc-scrape-examples = true
[[example]]
name = "checkbox_radio"
path = "examples/02-building-ui/checkbox_radio.rs"
doc-scrape-examples = true
[[example]]
name = "dynamic_classes"
path = "examples/02-building-ui/dynamic_classes.rs"
doc-scrape-examples = true
[[example]]
name = "event_handler_prop"
path = "examples/02-building-ui/event_handler_prop.rs"
doc-scrape-examples = true
[[example]]
name = "css_modules"
path = "examples/03-assets-styling/css_modules.rs"
@@ -600,8 +650,38 @@ path = "examples/03-assets-styling/meta.rs"
doc-scrape-examples = true
[[example]]
name = "meta_elements"
path = "examples/03-assets-styling/meta_elements.rs"
name = "stylesheet"
path = "examples/03-assets-styling/stylesheet.rs"
doc-scrape-examples = true
[[example]]
name = "document_title"
path = "examples/03-assets-styling/document_title.rs"
doc-scrape-examples = true
[[example]]
name = "favicon"
path = "examples/03-assets-styling/favicon.rs"
doc-scrape-examples = true
[[example]]
name = "inline_styles"
path = "examples/03-assets-styling/inline_styles.rs"
doc-scrape-examples = true
[[example]]
name = "dynamic_styles"
path = "examples/03-assets-styling/dynamic_styles.rs"
doc-scrape-examples = true
[[example]]
name = "fonts"
path = "examples/03-assets-styling/fonts.rs"
doc-scrape-examples = true
[[example]]
name = "script"
path = "examples/03-assets-styling/script.rs"
doc-scrape-examples = true
[[example]]
@@ -634,6 +714,41 @@ name = "errors"
path = "examples/04-managing-state/error_handling.rs"
doc-scrape-examples = true
[[example]]
name = "use_effect"
path = "examples/04-managing-state/use_effect.rs"
doc-scrape-examples = true
[[example]]
name = "use_memo"
path = "examples/04-managing-state/use_memo.rs"
doc-scrape-examples = true
[[example]]
name = "struct_signal"
path = "examples/04-managing-state/struct_signal.rs"
doc-scrape-examples = true
[[example]]
name = "vec_signal"
path = "examples/04-managing-state/vec_signal.rs"
doc-scrape-examples = true
[[example]]
name = "read_signal"
path = "examples/04-managing-state/read_signal.rs"
doc-scrape-examples = true
[[example]]
name = "lifting_state"
path = "examples/04-managing-state/lifting_state.rs"
doc-scrape-examples = true
[[example]]
name = "custom_hook"
path = "examples/04-managing-state/custom_hook.rs"
doc-scrape-examples = true
[[example]]
name = "backgrounded_futures"
path = "examples/05-using-async/backgrounded_futures.rs"
+2 -6
View File
@@ -164,10 +164,6 @@ We've put a ton of effort into building clean, readable, and comprehensive docum
</div>
## Modular and Customizable
Build your own renderer. Use our modular components like RSX, VirtualDom, Blitz, Taffy, and Subsecond.
## Community
Dioxus is a community-driven project, with a very active [Discord](https://discord.gg/XgGxMSkvUM) and [GitHub](https://github.com/DioxusLabs/dioxus/issues) community. We're always looking for help, and we're happy to answer questions and help you get started. [Our SDK](https://github.com/DioxusLabs/dioxus-std) is community-run and we even have a [GitHub organization](https://github.com/dioxus-community/) for the best Dioxus crates that receive free upgrades and support.
@@ -252,10 +248,10 @@ cargo run --example <example>
However, we encourage you to download the dioxus-cli to test out features like hot-reloading. To install the most recent binary CLI, you can use cargo binstall.
```sh
cargo binstall dioxus-cli@0.7.0 --force
curl -fsSL https://dioxuslabs.com/install.sh | bash
```
If this CLI is out-of-date, you can install it directly from git
If this CLI is out-of-date, you can install it directly from git or cargo-binstall
```sh
cargo install --git https://github.com/DioxusLabs/dioxus dioxus-cli --locked
+45
View File
@@ -0,0 +1,45 @@
//! Checkboxes and radio groups.
//!
//! Checkboxes expose their checked state through the FormEvent — read `evt.checked()`.
//! Radio groups share a `name` attribute so only one option can be selected at a time;
//! the selected value comes through `evt.value()`.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
let mut subscribed = use_signal(|| false);
let mut color = use_signal(|| "red".to_string());
rsx! {
h2 { "Checkbox" }
label {
input {
r#type: "checkbox",
checked: subscribed(),
oninput: move |evt| subscribed.set(evt.checked()),
}
" Subscribe to updates"
}
p { "Subscribed: {subscribed}" }
h2 { "Radio group" }
// Radio inputs sharing a `name` are mutually exclusive
for value in ["red", "green", "blue"] {
label {
input {
r#type: "radio",
name: "color",
value,
checked: color() == value,
oninput: move |evt| color.set(evt.value()),
}
" {value}"
}
}
p { color: "{color}", "Chosen color: {color}" }
}
}
+52
View File
@@ -0,0 +1,52 @@
//! Accepting children on a component.
//!
//! Any component can take a `children: Element` prop. Anything nested inside the component
//! in `rsx!` is passed in as `children`. This is how you build reusable layout and container
//! components like cards, modals, or page shells.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
rsx! {
Card {
h2 { "A card" }
p { "Any rsx! can go inside — including other components." }
}
Card {
p { "A second card with different children." }
button { "Click me" }
}
Section { title: "Reusable layout",
p { "The section component takes both a title prop and children." }
}
}
}
#[component]
fn Card(children: Element) -> Element {
rsx! {
div {
border: "1px solid #ccc",
border_radius: "8px",
padding: "12px",
margin: "8px 0",
{children}
}
}
}
#[component]
fn Section(title: String, children: Element) -> Element {
rsx! {
section {
h3 { "{title}" }
{children}
}
}
}
+46
View File
@@ -0,0 +1,46 @@
//! Defining and using components.
//!
//! A component is just a function annotated with `#[component]` that returns an `Element`.
//! Its arguments are its props — Dioxus generates a builder so you can construct the
//! component inside `rsx!` with a struct-like syntax.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
rsx! {
h1 { "Greetings" }
Greeting { name: "Alice" }
Greeting { name: "Bob", excited: true }
Greeting { name: "Charlie", excited: false }
h2 { "User cards" }
UserCard { name: "Ada Lovelace", role: "Mathematician" }
UserCard { name: "Grace Hopper", role: "Computer Scientist" }
}
}
// Components must start with an uppercase letter.
// Props are taken as named arguments — `name` is required, and `excited` has a default.
#[component]
fn Greeting(name: String, #[props(default)] excited: bool) -> Element {
let punctuation = if excited { "!" } else { "." };
rsx! {
p { "Hello, {name}{punctuation}" }
}
}
// Components can take any Clone + PartialEq type as a prop.
#[component]
fn UserCard(name: String, role: String) -> Element {
rsx! {
div { border: "1px solid #ccc", padding: "8px", margin: "4px",
strong { "{name}" }
" — "
em { "{role}" }
}
}
}
@@ -0,0 +1,52 @@
//! Conditional rendering.
//!
//! `if`, `else`, and `match` all work directly inside `rsx!`. You can also return different
//! `rsx!` blocks early from a component function. Elements outside of a conditional will
//! render normally — only the branched portion swaps as state changes.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
#[derive(PartialEq, Clone, Copy)]
enum Status {
Loading,
Ready,
Error,
}
fn app() -> Element {
let mut logged_in = use_signal(|| false);
let mut status = use_signal(|| Status::Loading);
rsx! {
h1 { "Conditional rendering" }
// `if/else` chains render the matching branch
if logged_in() {
p { "Welcome back!" }
} else {
p { "Please log in." }
}
button { onclick: move |_| logged_in.toggle(), "Toggle login" }
// `match` works too — each arm returns rsx!
div {
match status() {
Status::Loading => rsx! { p { "⏳ Loading..." } },
Status::Ready => rsx! { p { "✅ Ready!" } },
Status::Error => rsx! { p { "❌ Something went wrong." } },
}
}
button { onclick: move |_| status.set(Status::Loading), "Loading" }
button { onclick: move |_| status.set(Status::Ready), "Ready" }
button { onclick: move |_| status.set(Status::Error), "Error" }
// `if` without an `else` is also valid — nothing renders when false
if logged_in() && status() == Status::Ready {
p { "You are logged in and the app is ready." }
}
}
}
+22
View File
@@ -0,0 +1,22 @@
//! The classic counter — the "hello world" of reactive UI.
//!
//! `use_signal` creates a reactive value. Whenever the signal changes, any part of the UI
//! that reads it will re-render automatically. Signals are copy-cheap, so you can freely
//! move them into event handlers and closures.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
let mut count = use_signal(|| 0);
rsx! {
h1 { "Count: {count}" }
button { onclick: move |_| count += 1, "Increment" }
button { onclick: move |_| count -= 1, "Decrement" }
button { onclick: move |_| count.set(0), "Reset" }
}
}
@@ -0,0 +1,54 @@
//! Applying classes and styles based on state.
//!
//! Any attribute can interpolate signals and expressions using `"{value}"` formatting.
//! For `class:`, you can also build the class string inline with if/else, and individual
//! CSS properties can be set as named attributes like `color:` or `background_color:`.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
let mut is_active = use_signal(|| false);
let mut size = use_signal(|| 16);
// Build a class string from state
let classes = if is_active() { "btn active" } else { "btn" };
rsx! {
// CSS properties are plain named attributes — snake_case in Rust, kebab-case in CSS
style { {STYLE} }
button {
class: classes,
onclick: move |_| is_active.toggle(),
"Toggle active (currently {is_active})"
}
// Or compute the class string ahead of time for anything more complex
div {
class: if is_active() { "box highlight" } else { "box" },
"This box changes class with the button."
}
hr {}
// Style values can be driven directly by signals
p {
font_size: "{size}px",
color: if size() > 24 { "crimson" } else { "black" },
"Font size: {size}px"
}
button { onclick: move |_| size += 2, "Bigger" }
button { onclick: move |_| size -= 2, "Smaller" }
}
}
const STYLE: &str = r#"
.btn { padding: 6px 12px; border: 1px solid #888; border-radius: 4px; }
.btn.active { background: #4CAF50; color: white; border-color: #2E7D32; }
.box { padding: 12px; margin-top: 12px; border: 1px dashed #999; }
.box.highlight { background: #fff3cd; border-color: #d39e00; }
"#;
@@ -0,0 +1,45 @@
//! Passing event handlers as props.
//!
//! Components can accept callbacks using `EventHandler<T>`, which is Dioxus's equivalent
//! of React's `onClick` prop or a closure. Call the handler with `.call(value)` from the
//! child; the parent decides what happens when the event fires.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
let mut log = use_signal(Vec::<String>::new);
rsx! {
h1 { "Custom event handlers" }
// The parent owns the handler — the child just fires it
FancyButton {
label: "Say hi",
onpress: move |name: String| log.write().push(format!("Hi, {name}!")),
}
FancyButton {
label: "Say bye",
onpress: move |name: String| log.write().push(format!("Bye, {name}!")),
}
ul {
for entry in log.iter() {
li { "{entry}" }
}
}
}
}
#[component]
fn FancyButton(label: String, onpress: EventHandler<String>) -> Element {
rsx! {
button {
onclick: move |_| onpress.call(label.clone()),
"{label}"
}
}
}
+88
View File
@@ -0,0 +1,88 @@
//! Handling form submission and deserializing into a struct.
//!
//! `evt.parsed_values::<T>()` takes the form's named inputs and deserializes them straight
//! into your own type via serde. This skips the chore of pulling each field out of the
//! values map by hand — just define a struct whose fields match the `name` attributes,
//! derive `Deserialize`, and you're done.
use dioxus::prelude::*;
use serde::Deserialize;
fn main() {
dioxus::launch(app);
}
// Field names must match the `name` attribute on each input
#[derive(Deserialize, Debug, Clone)]
struct Signup {
username: String,
email: String,
role: String,
// Checkboxes are present in the form data only when checked, so model optional fields
// with Option<String>. Use `#[serde(default)]` so the field doesn't fail to deserialize
// when the input is missing.
#[serde(default)]
newsletter: Option<String>,
}
fn app() -> Element {
let mut submitted = use_signal(|| None::<Signup>);
rsx! {
h1 { "Sign up" }
form {
onsubmit: move |evt| {
// prevent_default stops the browser from navigating the page on submit
evt.prevent_default();
// Deserialize directly into our struct
match evt.parsed_values::<Signup>() {
Ok(signup) => submitted.set(Some(signup)),
Err(err) => eprintln!("failed to parse form: {err}"),
}
},
div {
label { r#for: "username", "Username: " }
input { r#type: "text", id: "username", name: "username", required: true }
}
div {
label { r#for: "email", "Email: " }
input { r#type: "email", id: "email", name: "email", required: true }
}
div {
label { r#for: "role", "Role: " }
select { id: "role", name: "role",
option { value: "developer", "Developer" }
option { value: "designer", "Designer" }
option { value: "manager", "Manager" }
}
}
div {
label { r#for: "newsletter",
input { r#type: "checkbox", id: "newsletter", name: "newsletter", value: "yes" }
" Subscribe to newsletter"
}
}
button { r#type: "submit", "Submit" }
}
if let Some(signup) = submitted() {
h2 { "Welcome, {signup.username}!" }
ul {
li { "Email: {signup.email}" }
li { "Role: {signup.role}" }
li { "Newsletter: {signup.newsletter.is_some()}" }
}
details {
summary { "Raw struct" }
pre { "{signup:#?}" }
}
}
}
}
+43
View File
@@ -0,0 +1,43 @@
//! Controlled text inputs.
//!
//! To read text from an input, attach an `oninput` handler and call `evt.value()` to get the
//! current value as a `String`. Binding the `value:` attribute to a signal makes the input
//! "controlled" — the signal is the single source of truth, so clearing it clears the input.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
let mut name = use_signal(String::new);
let mut message = use_signal(|| "Type something below.".to_string());
rsx! {
h1 { "Hello, {name}!" }
input {
r#type: "text",
placeholder: "Your name",
// Binding `value` to a signal makes this a controlled input
value: "{name}",
oninput: move |evt| name.set(evt.value()),
}
button {
onclick: move |_| name.set(String::new()),
"Clear"
}
hr {}
p { "{message}" }
textarea {
rows: 3,
cols: 40,
value: "{message}",
oninput: move |evt| message.set(evt.value()),
}
}
}
+53
View File
@@ -0,0 +1,53 @@
//! Rendering lists.
//!
//! Use a `for` loop inside `rsx!` to render a list from an iterator. When list items can
//! be reordered, added, or removed, provide a stable `key` so Dioxus can efficiently
//! reuse existing elements rather than re-rendering them all.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
let mut items = use_signal(|| {
vec![
"apple".to_string(),
"banana".to_string(),
"cherry".to_string(),
]
});
let mut next_id = use_signal(|| 0);
rsx! {
h1 { "Grocery list" }
button {
onclick: move |_| {
let n = next_id();
next_id += 1;
items.push(format!("item {n}"));
},
"Add item"
}
button {
onclick: move |_| { items.pop(); },
"Remove last"
}
ul {
// The `key` is a stable identifier used to match up items across renders.
// Here we use the item's text, but in real apps prefer a database id.
for item in items.iter() {
li { key: "{item}", "{item}" }
}
}
// You can also use iterator adapters with .map() for anything more complex than a for loop
p { "Uppercased:" }
ul {
{items.iter().map(|item| rsx! { li { "{item.to_uppercase()}" } })}
}
}
}
@@ -0,0 +1,27 @@
//! Setting the page title.
//!
//! The `Title` component renders a `<title>` tag into the document head. On the web it
//! sets the browser tab title; on desktop it becomes the window title. Because it's a
//! regular component, its contents can be driven by signals and update live.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
let mut unread = use_signal(|| 0);
rsx! {
// The title updates every time the signal changes
Title {
if unread() > 0 { "({unread}) Inbox" } else { "Inbox" }
}
h1 { "Inbox" }
p { "Unread messages: {unread}" }
button { onclick: move |_| unread += 1, "New message" }
button { onclick: move |_| unread.set(0), "Mark all read" }
}
}
@@ -0,0 +1,62 @@
//! Styling driven by state.
//!
//! Style attributes are interpolated the same way text is — read from signals inside `"{...}"`
//! or pass a conditional expression directly. The element re-renders only when the read
//! signals change, so you can freely animate colors, sizes, and transforms this way.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
let mut hue = use_signal(|| 200.0_f32);
let mut size = use_signal(|| 100.0_f32);
let mut rotated = use_signal(|| false);
rsx! {
h1 { "Dynamic styling" }
div {
width: "{size}px",
height: "{size}px",
background_color: "hsl({hue}, 80%, 60%)",
transition: "transform 300ms ease",
transform: if rotated() { "rotate(45deg)" } else { "rotate(0deg)" },
margin: "20px 0",
}
div {
label { "Hue: {hue:.0}" }
input {
r#type: "range",
min: "0",
max: "360",
value: "{hue}",
oninput: move |evt| {
if let Ok(v) = evt.value().parse::<f32>() {
hue.set(v);
}
},
}
}
div {
label { "Size: {size:.0}px" }
input {
r#type: "range",
min: "40",
max: "300",
value: "{size}",
oninput: move |evt| {
if let Ok(v) = evt.value().parse::<f32>() {
size.set(v);
}
},
}
}
button { onclick: move |_| rotated.toggle(), "Toggle rotation" }
}
}
+23
View File
@@ -0,0 +1,23 @@
//! Setting a favicon.
//!
//! Use `document::Link` with `rel: "icon"` to point the browser at a favicon. Combined with
//! `asset!`, the favicon is bundled into the app and served with the same path-mangling
//! and cache-busting as any other asset.
use dioxus::prelude::*;
const FAVICON: Asset = asset!("/examples/assets/logo.png");
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
rsx! {
// Link is a generic head element — for a favicon set rel="icon"
document::Link { rel: "icon", href: FAVICON }
h1 { "Check the browser tab!" }
p { "The favicon is loaded from examples/assets/logo.png." }
}
}
+44
View File
@@ -0,0 +1,44 @@
//! Loading fonts — from a CDN and bundled with the app.
//!
//! Two common ways to get a custom typeface onto the page:
//!
//! 1. Point `Stylesheet` at a hosted CSS file like Google Fonts — the browser fetches the
//! font files on demand.
//! 2. Bundle a font file into the app with `asset!`, then declare an `@font-face` rule
//! that points at it. This avoids the network round-trip and makes the font available
//! offline.
use dioxus::prelude::*;
// A local font, bundled into the app. The asset macro fingerprints and copies the file
// into the final build; at runtime `INTER` formats to the public URL.
const INTER: Asset = asset!("/examples/assets/Inter-Regular.woff2");
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
rsx! {
// Approach 1 — request a stylesheet from the Google Fonts CDN
Stylesheet { href: "https://fonts.googleapis.com/css2?family=Lobster&family=Roboto+Mono&display=swap" }
// Approach 2 — register a bundled font with an inline @font-face rule.
// `{INTER}` interpolates to the asset's resolved URL at runtime.
style { "@font-face {{ font-family: 'Inter'; src: url('{INTER}') format('woff2'); font-display: swap; }}" }
h1 { font_family: "'Lobster', cursive", font_size: "48px",
"From Google Fonts"
}
p { font_family: "'Roboto Mono', monospace",
"This paragraph also comes from the CDN."
}
hr {}
h2 { font_family: "'Inter', sans-serif", "Bundled Inter font" }
p { font_family: "'Inter', sans-serif",
"This paragraph uses Inter, shipped with the app — no network request needed."
}
}
}
@@ -0,0 +1,44 @@
//! Inline styles.
//!
//! For quick one-off styling, every CSS property is available as an attribute on HTML
//! elements — use snake_case in Rust (`background_color`) for the kebab-case CSS property
//! (`background-color`). You can also set the raw `style:` attribute with a full string.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
rsx! {
// Each CSS property is just a named attribute
div {
background_color: "#1e3a8a",
color: "white",
padding: "20px",
border_radius: "8px",
font_family: "system-ui, sans-serif",
h1 { "Inline styling" }
p { "Property names are snake_case here, kebab-case in real CSS." }
}
// The raw `style` attribute accepts any CSS string
div {
style: "margin-top: 12px; border: 2px dashed tomato; padding: 10px;",
"Use `style:` when you want a plain CSS string."
}
// Interpolation works too — great for values driven by Rust expressions
for i in 1..=5 {
span {
display: "inline-block",
width: "32px",
height: "32px",
margin: "4px",
background_color: "hsl({i * 60}, 70%, 55%)",
}
}
}
}
@@ -1,20 +0,0 @@
//! This example shows how to add metadata to the page with the Meta component
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
rsx! {
// You can use the Meta component to render a meta tag into the head of the page
// Meta tags are useful to provide information about the page to search engines and social media sites
// This example sets up meta tags for the open graph protocol for social media previews
Meta { property: "og:title", content: "My Site" }
Meta { property: "og:type", content: "website" }
Meta { property: "og:url", content: "https://www.example.com" }
Meta { property: "og:image", content: "https://example.com/image.jpg" }
Meta { name: "description", content: "My Site is a site" }
}
}
+34
View File
@@ -0,0 +1,34 @@
//! Adding a script to the document head.
//!
//! `document::Script` injects a `<script>` tag into the page. Use it to embed an inline
//! snippet via children, or load an external script by passing a `src`. Scripts are
//! deduplicated by their `src`, so mounting the same script from multiple components is safe.
//!
//! Prefer `Script` over `link {}` for better integration with SSR and pre-rendering.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
rsx! {
// Inline script — children must be a single text node
document::Script { "console.log('Hello from an inline script!');" }
// External script, loaded with `defer` so it runs after parsing
document::Script { src: "https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.3/dist/confetti.browser.min.js", defer: true }
h1 { "Script example" }
p { "Open your browser's console to see the inline script's output." }
button {
onclick: move |_| {
// Call out to the confetti library loaded above
document::eval("confetti && confetti();");
},
"🎉 Confetti"
}
}
}
+24
View File
@@ -0,0 +1,24 @@
//! Linking a CSS stylesheet.
//!
//! `Stylesheet` renders a `<link rel="stylesheet">` into the document head. Pairing it with
//! the `asset!` macro is the most common way to style a Dioxus app: the CSS file is bundled,
//! fingerprinted for cache-busting, and can be hot-reloaded during development.
use dioxus::prelude::*;
const STYLE: Asset = asset!("/examples/assets/stylesheet.css");
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
rsx! {
// Placing the Stylesheet anywhere in the tree is fine — it's collected into <head>
Stylesheet { href: STYLE }
h1 { "Styled with a CSS file" }
p { "All styling comes from stylesheet.css, loaded via the asset! macro." }
button { "A styled button" }
}
}
+59
View File
@@ -0,0 +1,59 @@
//! Writing your own hook.
//!
//! A hook is just a function that calls other hooks. By convention it starts with `use_`
//! and returns whatever state handle the caller needs. Extracting hooks is how you reuse
//! stateful logic across components — like a counter, a timer, or a data fetcher.
//!
//! Hooks rely on being called in the same order every render, so never call them inside
//! `if`, `match`, or loops.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
// Each call to our custom hook produces an independent counter
let mut counter_a = use_counter(0);
let mut counter_b = use_counter(100);
// And a more complex hook that exposes multiple actions
let (name, set_name, reverse) = use_reversible_name("Ada");
rsx! {
h2 { "Two counters from one hook" }
p { "A: {counter_a}" }
button { onclick: move |_| counter_a += 1, "Increment A" }
p { "B: {counter_b}" }
button { onclick: move |_| counter_b += 1, "Increment B" }
h2 { "Reversible name" }
input {
value: "{name}",
oninput: move |evt| set_name.call(evt.value()),
}
button { onclick: move |_| reverse.call(()), "Reverse" }
p { "Name: {name}" }
}
}
// A minimal hook — returns a signal initialized with a value
fn use_counter(initial: i32) -> Signal<i32> {
use_signal(|| initial)
}
// Hooks can return any combination of signals and callbacks
fn use_reversible_name(initial: &'static str) -> (Signal<String>, Callback<String>, Callback<()>) {
let mut name = use_signal(|| initial.to_string());
// `use_callback` memoizes a closure so children don't think it changed every render
let set_name = use_callback(move |value: String| name.set(value));
let reverse = use_callback(move |_| {
let reversed = name.read().chars().rev().collect::<String>();
name.set(reversed);
});
(name, set_name, reverse)
}
@@ -0,0 +1,47 @@
//! Sharing state between sibling components by lifting it up.
//!
//! When two components need to read or edit the same value, put the signal in their
//! common parent and pass it down as a prop. This keeps the data flow obvious: the parent
//! owns the state, the children receive a `Signal<T>` handle, and mutations show up
//! everywhere the signal is read.
//!
//! For state that needs to be shared across many layers, reach for `use_context_provider`
//! instead — see `context_api.rs`.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
// The parent owns the signal; both children share it
let counter = use_signal(|| 0);
rsx! {
h1 { "Two views of the same counter" }
Controls { counter }
Display { counter }
}
}
#[component]
fn Controls(mut counter: Signal<i32>) -> Element {
rsx! {
button { onclick: move |_| counter += 1, "Increment" }
button { onclick: move |_| counter -= 1, "Decrement" }
button { onclick: move |_| counter.set(0), "Reset" }
}
}
#[component]
fn Display(counter: Signal<i32>) -> Element {
rsx! {
p { "Count is: {counter}" }
p {
if counter() > 0 { "Positive" }
else if counter() < 0 { "Negative" }
else { "Zero" }
}
}
}
+37
View File
@@ -0,0 +1,37 @@
//! Passing a read-only signal to a child component.
//!
//! `ReadSignal<T>` is a signal that can only be read, not written. Taking it as a prop is
//! the idiomatic way to tell a child "you can subscribe to this value, but you can't change
//! it." Any `Signal<T>` or `Memo<T>` coerces into a `ReadSignal<T>` automatically, so the
//! parent passes them in unchanged.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
let mut count = use_signal(|| 0);
let doubled = use_memo(move || count() * 2);
rsx! {
h1 { "Parent" }
button { onclick: move |_| count += 1, "Increment" }
// Both Signal and Memo implement Into<ReadSignal<T>>
Display { label: "Count", value: count }
Display { label: "Doubled", value: doubled }
// You can also pass a plain value — it'll be wrapped automatically
Display { label: "Constant", value: 42 }
}
}
// Taking `ReadSignal<i32>` means the child can subscribe but can't mutate the source
#[component]
fn Display(label: String, value: ReadSignal<i32>) -> Element {
rsx! {
p { "{label}: {value}" }
}
}
@@ -0,0 +1,61 @@
//! A signal that holds a struct.
//!
//! Signals don't care what they hold — you can put any `'static` type inside. To mutate
//! a field on a struct signal, call `.write()` and the guard derefs to the inner value.
//! Any read of the signal in the UI will re-render when you drop the write guard.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
#[derive(Clone)]
struct User {
name: String,
age: u32,
admin: bool,
}
fn app() -> Element {
let mut user = use_signal(|| User {
name: "Ada".to_string(),
age: 36,
admin: false,
});
rsx! {
h1 { "User profile" }
p { "Name: {user.read().name}" }
p { "Age: {user.read().age}" }
p { "Admin: {user.read().admin}" }
button {
// .write() gives a mutable guard — assign to a single field
onclick: move |_| user.write().age += 1,
"Happy birthday!"
}
button {
onclick: move |_| {
let mut guard = user.write();
guard.admin = !guard.admin;
},
"Toggle admin"
}
input {
value: "{user.read().name}",
oninput: move |evt| user.write().name = evt.value(),
}
// Replacing the whole value works too
button {
onclick: move |_| user.set(User {
name: "Grace".to_string(),
age: 85,
admin: true,
}),
"Reset to Grace"
}
}
}
+40
View File
@@ -0,0 +1,40 @@
//! Running side effects when state changes.
//!
//! `use_effect` runs a closure after every render where one of the signals it reads has
//! changed. It's the escape hatch for talking to code outside of Dioxus — logging, syncing
//! to `localStorage`, updating the `document.title`, tweaking imperative APIs, and so on.
//!
//! For pure derivations of other signals, reach for `use_memo` instead — effects are meant
//! for side effects, not for computing values used in the UI.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
let mut count = use_signal(|| 0);
let mut name = use_signal(|| "world".to_string());
// Runs after every render where `count` changes — use this for side effects
use_effect(move || {
println!("count is now {count}");
});
// An effect can read multiple signals. It re-runs whenever any of them change.
use_effect(move || {
println!("greeting changed: hello, {name} — count is {count}");
});
rsx! {
h1 { "Hello, {name}! ({count})" }
button { onclick: move |_| count += 1, "Increment count" }
input {
value: "{name}",
oninput: move |evt| name.set(evt.value()),
}
p { "Check your terminal — each change fires an effect." }
}
}
+39
View File
@@ -0,0 +1,39 @@
//! Deriving values with `use_memo`.
//!
//! `use_memo` caches the result of a closure and re-runs it only when one of the signals
//! it reads changes. It's how you compute values derived from state without doing the work
//! on every render, and without introducing another `use_signal` that you have to keep
//! in sync manually.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
let mut first = use_signal(|| "Ada".to_string());
let mut last = use_signal(|| "Lovelace".to_string());
// Recomputes only when `first` or `last` change
let full_name = use_memo(move || format!("{first} {last}"));
// Memos compose — derive from other memos or signals
let initials = use_memo(move || {
let name = full_name();
name.split_whitespace()
.filter_map(|w| w.chars().next())
.collect::<String>()
});
rsx! {
h1 { "{full_name}" }
p { "Initials: {initials}" }
label { "First: " }
input { value: "{first}", oninput: move |e| first.set(e.value()) }
label { "Last: " }
input { value: "{last}", oninput: move |e| last.set(e.value()) }
}
}
+62
View File
@@ -0,0 +1,62 @@
//! Signals that hold a collection.
//!
//! `Signal<Vec<T>>` is the workhorse for dynamic lists. Dioxus exposes `push`, `pop`,
//! `remove`, `clear`, and `retain` directly on the signal so you don't have to call
//! `.write()` for the common cases. For anything else, `.write()` returns a guard that
//! derefs to the underlying `Vec`.
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
let mut todos = use_signal(|| vec!["learn dioxus".to_string(), "build an app".to_string()]);
let mut draft = use_signal(String::new);
rsx! {
h1 { "Todo list" }
input {
placeholder: "New todo...",
value: "{draft}",
oninput: move |evt| draft.set(evt.value()),
}
button {
onclick: move |_| {
if !draft.read().is_empty() {
todos.push(draft());
draft.set(String::new());
}
},
"Add"
}
ul {
for (index, todo) in todos.read().iter().enumerate() {
li { key: "{index}",
"{todo} "
button {
onclick: move |_| { todos.remove(index); },
"×"
}
}
}
}
button { onclick: move |_| todos.clear(), "Clear all" }
button {
// `.retain` accepts a predicate — here we drop any todo containing "x"
onclick: move |_| todos.retain(|t| !t.contains('x')),
"Drop todos with 'x'"
}
button {
// For anything custom, `.write()` gives a mutable guard to the Vec
onclick: move |_| todos.write().sort(),
"Sort alphabetically"
}
p { "{todos.len()} todo(s)" }
}
}
Binary file not shown.
+21
View File
@@ -0,0 +1,21 @@
body {
font-family: system-ui, sans-serif;
background: #fafafa;
color: #222;
max-width: 640px;
margin: 40px auto;
padding: 0 16px;
}
h1 { color: #1e3a8a; }
button {
padding: 6px 14px;
border: 1px solid #1e3a8a;
border-radius: 4px;
background: white;
color: #1e3a8a;
cursor: pointer;
}
button:hover { background: #1e3a8a; color: white; }
+160 -207
View File
@@ -1,229 +1,182 @@
<div align="center">
<img
src="https://github.com/user-attachments/assets/6c7e227e-44ff-4e53-824a-67949051149c"
alt="Build web, desktop, and mobile apps with a single codebase."
width="100%"
class="darkmode-image"
>
<div>
<a href=https://dioxuslabs.com/learn/0.7/getting_started>Getting Started</a> | <a href="https://dioxuslabs.com/learn/0.7/">Book (0.7)</a> | <a href="https://github.com/DioxusLabs/dioxus/tree/main/examples">Examples</a>
</div>
<img src="https://raw.githubusercontent.com/DioxusLabs/dioxus/main/notes/splash-header.svg" style="width: 80%; height: auto;">
</div>
<div align="center">
<!-- Crates version -->
<a href="https://crates.io/crates/dioxus">
<img src="https://img.shields.io/crates/v/dioxus.svg?style=flat-square"
alt="Crates.io version" />
</a>
<!-- Downloads -->
<a href="https://crates.io/crates/dioxus">
<img src="https://img.shields.io/crates/d/dioxus.svg?style=flat-square"
alt="Download" />
</a>
<!-- docs -->
<a href="https://docs.rs/dioxus">
<img src="https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square"
alt="docs.rs docs" />
</a>
<!-- CI -->
<a href="https://github.com/dioxuslabs/dioxus/actions">
<img src="https://github.com/dioxuslabs/dioxus/actions/workflows/main.yml/badge.svg"
alt="CI status" />
</a>
<!-- Awesome -->
<a href="https://dioxuslabs.com/awesome">
<img src="https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg" alt="Awesome Page" />
</a>
<!-- Discord -->
<a href="https://discord.gg/XgGxMSkvUM">
<img src="https://img.shields.io/discord/899851952891002890.svg?logo=discord&style=flat-square" alt="Discord Link" />
</a>
</div>
<div align="center">
<h3>
<a href="https://dioxuslabs.com"> Website </a>
<span> | </span>
<a href="https://dioxuslabs.com/learn/0.7/getting_started"> Getting Started </a>
<span> | </span>
<a href="https://dioxuslabs.com/learn/0.7/"> Book (0.7) </a>
<span> | </span>
<a href="https://github.com/DioxusLabs/dioxus/tree/main/examples"> Examples </a>
<span> | </span>
<a href="https://dioxuslabs.com/learn/0.7/tutorial"> Tutorial </a>
</h3>
</div>
---
Dioxus is a framework for building cross-platform apps in Rust. With one codebase, you can build web, desktop, and mobile apps with fullstack server functions. Dioxus is designed to be easy to learn for developers familiar with web technologies like HTML, CSS, and JavaScript.
Build for web, desktop, and mobile, and more with a single codebase. Zero-config setup, integrated hot-reloading, and signals-based state management. Add backend functionality with Server Functions and bundle with our CLI.
<div align="center">
<img src="https://github.com/user-attachments/assets/dddae6a9-c13b-4a88-84e8-dc98c1286d2a" alt="App with dioxus" height="600px">
</div>
## At a glance
Dioxus is crossplatform app framework that empowers developer to build beautiful, fast, type-safe apps with Rust. By default, Dioxus apps are declared with HTML and CSS. Dioxus includes a number of useful features:
- Hotreloading of RSX markup and assets
- Interactive CLI with logging, project templates, linting, and more
- Integrated bundler for deploying to the web, macOS, Linux, and Windows
- Support for modern web features like SSR, Hydration, and HTML streaming
- Direct access to system APIs through JNI (Android), CoreFoundation (Apple), and web-sys (web)
- Type-safe application routing and server functions
## Quick start
To get started with Dioxus, you'll want to grab the dioxus-cli tool: `dx`. We distribute `dx` with `cargo-binstall` - if you already have binstall skip this step.
```shell
# skip if you already have cargo-binstall
cargo install cargo-binstall
# install the precompiled `dx` tool
cargo binstall dioxus-cli
# create a new app, following the template
dx new my-app && cd my-app
# and then serve!
dx serve --desktop
```
## Your first app
All Dioxus apps are built by composing functions return an `Element`.
To launch an app, we use the `launch` method. In the launch function, we pass the app's root `Component`.
```rust, no_run
```rust, ignore
use dioxus::prelude::*;
fn main() {
dioxus::launch(App);
dioxus::launch(app);
}
// The #[component] attribute streamlines component creation.
// It's not required, but highly recommended. It will lint incorrect component definitions and help you create props structs.
#[component]
fn App() -> Element {
rsx! { "hello world!" }
}
```
## Elements & your first component
You can use the `rsx!` macro to create elements with a jsx-like syntax.
Any element in `rsx!` can have attributes, listeners, and children. For
consistency, we force all attributes and listeners to be listed _before_
children.
```rust, no_run
# use dioxus::prelude::*;
let value = "123";
rsx! {
div {
class: "my-class {value}", // <--- attribute
onclick: move |_| println!("clicked!"), // <--- listener
h1 { "hello world" } // <--- child
}
};
```
The `rsx!` macro accepts attributes in "struct form". Any rust expression contained within curly braces that implements [`IntoDynNode`](dioxus_core::IntoDynNode) will be parsed as a child. We make two exceptions: both `for` loops and `if` statements are parsed where their body is parsed as a rsx nodes.
```rust, no_run
# use dioxus::prelude::*;
rsx! {
div {
for _ in 0..10 {
span { "hello world" }
}
}
};
```
Putting everything together, we can write a simple component that renders a list of
elements:
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn App() -> Element {
let name = "dave";
rsx! {
h1 { "Hello, {name}!" }
div { class: "my-class", id: "my-id",
for i in 0..5 {
div { "FizzBuzz: {i}" }
}
}
}
}
```
## Components
We can compose these function components to build a complex app. Each new component takes some Properties. For components with no explicit properties, we can omit the type altogether.
In Dioxus, all properties are memoized by default with `Clone` and `PartialEq`. For props you can't clone, simply wrap the fields in a [`ReadSignal`](dioxus_signals::ReadSignal) and Dioxus will handle converting types for you.
```rust, no_run
# use dioxus::prelude::*;
# #[component] fn Header(title: String, color: String) -> Element { todo!() }
#[component]
fn App() -> Element {
rsx! {
Header {
title: "My App",
color: "red",
}
}
}
```
The `#[component]` macro will help us automatically create a props struct for our component:
```rust, no_run
# use dioxus::prelude::*;
// The component macro turns the arguments for our function into named fields we can pass in to the component in rsx
#[component]
fn Header(title: String, color: String) -> Element {
rsx! {
div {
background_color: "{color}",
h1 { "{title}" }
}
}
}
```
> You can read more about props in the [reference](https://dioxuslabs.com/learn/0.7/essentials/ui/components).
## Hooks
While components are reusable forms of UI elements, hooks are reusable forms of logic. Hooks provide a way of retrieving state from Dioxus' internal `Scope` and using
it to render UI elements.
By convention, all hooks are functions that should start with `use_`. We can use hooks to define the state and modify it from within listeners.
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn App() -> Element {
// The use signal hook runs once when the component is created and then returns the current value every run after the first
let name = use_signal(|| "world");
rsx! { "hello {name}!" }
}
```
Hooks are sensitive to how they are used. To use hooks, you must abide by the ["rules of hooks"](https://dioxuslabs.com/learn/0.7/essentials/basics/hooks#rules-of-hooks):
- Hooks can only be called in the body of a component or another hook. Not inside of another expression like a loop, conditional or function call.
- Hooks should start with "use\_"
Hooks let us add a field of state to our component without declaring an explicit state struct. However, this means we need to "load" the struct in the right order. If that order is wrong, then the hook will pick the wrong state and panic.
Dioxus includes many built-in hooks that you can use in your components. If those hooks don't fit your use case, you can also extend Dioxus with custom hooks.
## Putting it all together
Using components, rsx, and hooks, we can build a simple app.
```rust, no_run
use dioxus::prelude::*;
fn main() {
dioxus::launch(App);
}
#[component]
fn App() -> Element {
fn app() -> Element {
let mut count = use_signal(|| 0);
rsx! {
div { "Count: {count}" }
button { onclick: move |_| count += 1, "Increment" }
button { onclick: move |_| count -= 1, "Decrement" }
h1 { "High-Five counter: {count}" }
button { onclick: move |_| count += 1, "Up high!" }
button { onclick: move |_| count -= 1, "Down low!" }
}
}
```
## Conclusion
## ⭐️ Unique features
This overview doesn't cover everything. Make sure to check out the [tutorial](https://dioxuslabs.com/learn/0.7/tutorial) and [guides](https://dioxuslabs.com/learn/0.7/tutorial) on the official
website for more details.
- Cross-platform apps in three lines of code (web, desktop, mobile, server, and more)
- [Ergonomic state management](https://dioxuslabs.com/blog/release-050) combines the best of React, Solid, and Svelte
- Built-in featureful, type-safe, fullstack web framework
- Integrated bundler for deploying to the web, macOS, Linux, and Windows
- Subsecond Rust hot-patching and asset hot-reloading
- And more! [Take a tour of Dioxus](https://dioxuslabs.com/learn/0.7/).
Beyond this overview, Dioxus supports:
## Quick start
- Server-side rendering
- Concurrent rendering (with async support)
- Web/Desktop/Mobile support
- Pre-rendering and hydration
- Fragments, and Suspense
- Inline-styles
- Custom event handlers
- Custom elements
- Basic fine-grained reactivity (IE SolidJS/Svelte)
- and more!
Grab the Dioxus CLI (`dx`) and spin up a new app in seconds:
Build cool things ✌️
```shell
# install the dioxus-cli
curl -fsSL https://dioxuslabs.com/install.sh | bash
# create a new app, following the template instructions
dx new my-app && cd my-app
# and then serve on `--web, --desktop, --ios, or --android`
dx serve --desktop
```
## Guides
This overview doesn't cover everything. Make sure to check out:
- [Long-form tutorial](https://dioxuslabs.com/learn/0.7/tutorial)
- [Core concept guide](https://dioxuslabs.com/learn/0.7/essentials/)
- [Platform-specific guides](https://dioxuslabs.com/learn/0.7/guides/)
- [Code examples on GitHub](https://github.com/DioxusLabs/dioxus/tree/main/examples)
## Instant hot-reloading
With one command, `dx serve` and your app is running. Edit your markup, styles, and see changes in milliseconds. Use our experimental `dx serve --hotpatch` to update Rust code in real time.
<div align="center">
<img src="https://raw.githubusercontent.com/DioxusLabs/screenshots/refs/heads/main/blitz/hotreload-video.webp">
</div>
## Build Beautiful Apps
Dioxus apps are styled with HTML and CSS. Use the built-in TailwindCSS support or load your favorite CSS library. Easily call into native code (objective-c, JNI, Web-Sys) for a perfect native touch.
<div align="center">
<img src="https://raw.githubusercontent.com/DioxusLabs/dioxus/main/notes/ebou2.avif">
</div>
## Truly fullstack applications
Dioxus deeply integrates with [axum](https://github.com/tokio-rs/axum) to provide powerful fullstack capabilities for both clients and servers. Pick from a wide array of built-in batteries like WebSockets, SSE, Streaming, File Upload/Download, Server-Side-Rendering, Forms, Middleware, and Hot-Reload, or go fully custom and integrate your existing axum backend.
<div align="center">
<img src="https://raw.githubusercontent.com/DioxusLabs/dioxus/main/notes/fullstack-websockets.avif" width="700">
</div>
## Experimental Native Renderer
Render using web-sys, webview, server-side-rendering, liveview, or even with our experimental WGPU-based renderer. Embed Dioxus in Bevy, WGPU, or even run on embedded Linux!
<div align="center">
<img src="https://raw.githubusercontent.com/DioxusLabs/screenshots/refs/heads/main/blitz/native-blitz-wgpu.webp">
</div>
## First-party primitive components
Get started quickly with a complete set of primitives modeled after shadcn/ui and Radix-Primitives.
<div align="center">
<img src="https://raw.githubusercontent.com/DioxusLabs/dioxus/main/notes/primitive-components.avif" width="700">
</div>
## First-class Android and iOS support
Dioxus is the fastest way to build native mobile apps with Rust. Simply run `dx serve --platform android` and your app is running in an emulator or on device in seconds. Call directly into JNI and Native APIs.
<div align="center">
<img src="https://raw.githubusercontent.com/DioxusLabs/dioxus/main/notes/android_and_ios2.avif" width="500">
</div>
## Bundle for web, desktop, and mobile
Simply run `dx bundle` and your app will be built and bundled with maximization optimizations. On the web, take advantage of [`.avif` generation, `.wasm` compression, minification](https://dioxuslabs.com/learn/0.7/tutorial/assets), and more. Build WebApps weighing [less than 50kb](https://github.com/ealmloff/tiny-dioxus/) and desktop/mobile apps less than 5mb.
<div align="center">
<img src="https://raw.githubusercontent.com/DioxusLabs/dioxus/main/notes/bundle.gif">
</div>
## Fantastic documentation
We've put a ton of effort into building clean, readable, and comprehensive documentation. All html elements and listeners are documented with MDN docs, and our Docs runs continuous integration with Dioxus itself to ensure that the docs are always up to date. Check out the [Dioxus website](https://dioxuslabs.com/learn/0.7/) for guides, references, recipes, and more.
<div align="center">
<img src="https://raw.githubusercontent.com/DioxusLabs/dioxus/main/notes/docs.avif">
</div>
## Community
Dioxus is a community-driven project, with a very active [Discord](https://discord.gg/XgGxMSkvUM) and [GitHub](https://github.com/DioxusLabs/dioxus/issues) community. We're always looking for help, and we're happy to answer questions and help you get started. [Our SDK](https://github.com/DioxusLabs/dioxus-std) is community-run and we even have a [GitHub organization](https://github.com/dioxus-community/) for the best Dioxus crates that receive free upgrades and support.
<div align="center">
<img src="https://raw.githubusercontent.com/DioxusLabs/dioxus/main/notes/dioxus-community.avif">
</div>
## License
This project is licensed under either the [MIT license](https://github.com/DioxusLabs/dioxus/blob/main/LICENSE-MIT) or the [Apache-2 License](https://github.com/DioxusLabs/dioxus/blob/main/LICENSE-APACHE).
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Dioxus by you, shall be licensed as MIT or Apache-2, without any additional terms or conditions.