Просмотр исходного кода

Rework Guide (#486)

* Move getting started to Guide

* Clean up summary and getting started

* Shorten intro by moving stuff to individual platform docs

* Make intro even shorter, summarize features

* Further cleanup; move development-related docs to separate section

* Make `guide` a crate. Turn code samples into examples so that we can check if they compile

* Rewrite "Describing the UI":

* Focus on RSX syntax (interactivity covered in later chapters); make sure samples are tested; concise language

* Move some "special attribute" samples to the `examples` directory

* Simplify introduction to components

* Simplify introduction to component props

* Document Prop features; add code samples

* Simplify component children docs

* Interactivity: better introduction to events

* Hooks: better introduction

* Remove outdated doc

* Introducs use_ref

* Simplify User Input chapter

* Document event handler props

* Meme editor example

* Meme editor walkthrough

* Add dark mode example

* Guide for context; dark mode example

* Guide: custom hooks

* Guide: conditional rendering

* Guide: rendering lists

* Guide: rendering lists + keys

* Move remaining infor from Reference to guide

* Delete reference book
Reinis Mazeiks 3 лет назад
Родитель
Сommit
6c323e9fc5
100 измененных файлов с 2457 добавлено и 2526 удалено
  1. 1 0
      Cargo.toml
  2. 12 0
      docs/guide/Cargo.toml
  3. 1 1
      docs/guide/book.toml
  4. 1 0
      docs/guide/examples/Readme.md
  5. 71 0
      docs/guide/examples/anti_patterns.rs
  6. 17 0
      docs/guide/examples/boolean_attribute.rs
  7. 27 0
      docs/guide/examples/component_borrowed_props.rs
  8. 36 0
      docs/guide/examples/component_children.rs
  9. 37 0
      docs/guide/examples/component_children_inspect.rs
  10. 36 0
      docs/guide/examples/component_element_props.rs
  11. 34 0
      docs/guide/examples/component_owned_props.rs
  12. 113 0
      docs/guide/examples/component_props_options.rs
  13. 24 0
      docs/guide/examples/components.rs
  14. 60 0
      docs/guide/examples/conditional_rendering.rs
  15. 19 0
      docs/guide/examples/dangerous_inner_html.rs
  16. 17 0
      docs/guide/examples/event_click.rs
  17. 33 0
      docs/guide/examples/event_handler_prop.rs
  18. 24 0
      docs/guide/examples/event_nested.rs
  19. 17 0
      docs/guide/examples/event_prevent_default.rs
  20. 18 0
      docs/guide/examples/hello_world_desktop.rs
  21. 20 0
      docs/guide/examples/hello_world_tui.rs
  22. 36 0
      docs/guide/examples/hello_world_tui_no_ctrl_c.rs
  23. 14 0
      docs/guide/examples/hello_world_web.rs
  24. 67 0
      docs/guide/examples/hooks_bad.rs
  25. 13 0
      docs/guide/examples/hooks_composed.rs
  26. 18 0
      docs/guide/examples/hooks_counter.rs
  27. 24 0
      docs/guide/examples/hooks_counter_two_state.rs
  28. 23 0
      docs/guide/examples/hooks_use_ref.rs
  29. 21 0
      docs/guide/examples/input_controlled.rs
  30. 22 0
      docs/guide/examples/input_uncontrolled.rs
  31. 105 0
      docs/guide/examples/meme_editor.rs
  32. 184 0
      docs/guide/examples/meme_editor_dark_mode.rs
  33. 60 0
      docs/guide/examples/rendering_lists.rs
  34. 109 0
      docs/guide/examples/rsx_overview.rs
  35. 84 0
      docs/guide/examples/spawn.rs
  36. 60 0
      docs/guide/examples/use_future.rs
  37. 0 105
      docs/guide/src/README.md
  38. 33 44
      docs/guide/src/SUMMARY.md
  39. 6 0
      docs/guide/src/__unused/README.md
  40. 0 0
      docs/guide/src/__unused/advanced-guides/06-subscription-api.md
  41. 0 0
      docs/guide/src/__unused/advanced-guides/10-concurrent-mode.md
  42. 2 2
      docs/guide/src/__unused/advanced-guides/11-arena-memo.md
  43. 3 3
      docs/guide/src/__unused/advanced-guides/12-signals.md
  44. 2 2
      docs/guide/src/__unused/advanced-guides/13-subtrees.md
  45. 3 3
      docs/guide/src/__unused/advanced-guides/custom-renderer.md
  46. 1 1
      docs/guide/src/__unused/advanced-guides/liveview.md
  47. 3 3
      docs/guide/src/__unused/advanced-guides/rsx.md
  48. 1 1
      docs/guide/src/__unused/advanced-guides/testing.md
  49. 29 0
      docs/guide/src/__unused/attribute_spreading.md
  50. 1 1
      docs/guide/src/__unused/composing.md
  51. 26 0
      docs/guide/src/__unused/event_javascript.rs
  52. 2 2
      docs/guide/src/__unused/fanout.md
  53. 14 0
      docs/guide/src/__unused/hello_world.md
  54. 4 4
      docs/guide/src/__unused/helpers.md
  55. 3 3
      docs/guide/src/__unused/index.md
  56. 3 3
      docs/guide/src/__unused/localstate.md
  57. 28 0
      docs/guide/src/__unused/memoization.md
  58. 67 0
      docs/guide/src/__unused/model_pattern.md
  59. 0 73
      docs/guide/src/advanced-guides/00-index.md
  60. 0 229
      docs/guide/src/advanced-guides/rsx_in_depth.md
  61. 0 90
      docs/guide/src/async/asynctasks.md
  62. 2 97
      docs/guide/src/async/index.md
  63. 0 8
      docs/guide/src/async/loading_state.md
  64. 29 0
      docs/guide/src/async/spawn.md
  65. 2 2
      docs/guide/src/async/use_coroutine.md
  66. 14 66
      docs/guide/src/async/use_future.md
  67. 33 0
      docs/guide/src/best_practices/antipatterns.md
  68. 1 1
      docs/guide/src/best_practices/error_handling.md
  69. 29 0
      docs/guide/src/best_practices/index.md
  70. 0 218
      docs/guide/src/components/component_children.md
  71. BIN
      docs/guide/src/components/component_example_title.png
  72. BIN
      docs/guide/src/components/component_example_votes.png
  73. 0 292
      docs/guide/src/components/exporting_components.md
  74. 0 42
      docs/guide/src/components/index.md
  75. 0 232
      docs/guide/src/components/propsmacro.md
  76. 20 0
      docs/guide/src/contributing.md
  77. 2 2
      docs/guide/src/custom_renderer/index.md
  78. 31 0
      docs/guide/src/describing_ui/component_children.md
  79. 141 0
      docs/guide/src/describing_ui/component_props.md
  80. 27 0
      docs/guide/src/describing_ui/components.md
  81. BIN
      docs/guide/src/describing_ui/images/component_borrowed_props_screenshot.png
  82. BIN
      docs/guide/src/describing_ui/images/component_owned_props_screenshot.png
  83. BIN
      docs/guide/src/describing_ui/images/screenshot_about_component.png
  84. 106 0
      docs/guide/src/describing_ui/index.md
  85. 63 0
      docs/guide/src/describing_ui/special_attributes.md
  86. 0 184
      docs/guide/src/elements/conditional_rendering.md
  87. 0 73
      docs/guide/src/elements/index.md
  88. 0 145
      docs/guide/src/elements/lists.md
  89. 0 191
      docs/guide/src/elements/special_attributes.md
  90. 0 175
      docs/guide/src/elements/vnodes.md
  91. 0 49
      docs/guide/src/final.md
  92. 45 0
      docs/guide/src/getting_started/desktop.md
  93. 2 1
      docs/guide/src/getting_started/hot_reload.md
  94. 74 0
      docs/guide/src/getting_started/index.md
  95. 10 14
      docs/guide/src/getting_started/mobile.md
  96. 19 12
      docs/guide/src/getting_started/ssr.md
  97. 46 0
      docs/guide/src/getting_started/tui.md
  98. 72 0
      docs/guide/src/getting_started/web.md
  99. 0 152
      docs/guide/src/hello_world.md
  100. BIN
      docs/guide/src/images/01-setup-helloworld.png

+ 1 - 0
Cargo.toml

@@ -72,6 +72,7 @@ members = [
     "packages/native-core",
     "packages/native-core-macro",
     "packages/rsx-prelude",
+    "docs/guide",
 ]
 
 [dev-dependencies]

+ 12 - 0
docs/guide/Cargo.toml

@@ -0,0 +1,12 @@
+[package]
+name = "dioxus-guide"
+version = "0.0.1"
+edition = "2021"
+description = "Dioxus guide, including testable examples"
+license = "MIT/Apache-2.0"
+
+[dev-dependencies]
+dioxus = { path = "../..", features = ["desktop", "web", "ssr", "router", "fermi", "tui"] }
+serde = { version = "1.0.138", features=["derive"] }
+reqwest = { version = "0.11.11", features = ["json"] }
+tokio = { version = "1.19.2" , features=[]}

+ 1 - 1
docs/guide/book.toml

@@ -1,6 +1,6 @@
 [book]
 title = "Dioxus Documentation"
-description = "Create book from markdown files. Like Gitbook but implemented in Rust"
+description = "Get started with Dioxus, a portable, performant, and ergonomic framework for building cross-platform user interfaces in Rust"
 authors = ["Jonathan Kelley"]
 language = "en"
 

+ 1 - 0
docs/guide/examples/Readme.md

@@ -0,0 +1 @@
+Some of these examples (e.g. web) cannot be run. The code samples are here mostly so that we can easily check that they compile using `cargo test`.

+ 71 - 0
docs/guide/examples/anti_patterns.rs

@@ -0,0 +1,71 @@
+#![allow(non_snake_case, unused)]
+
+//! This example shows what *not* to do
+
+use std::collections::HashMap;
+
+use dioxus::prelude::*;
+
+fn main() {}
+
+fn AntipatternNestedFragments(cx: Scope<()>) -> Element {
+    // ANCHOR: nested_fragments
+    // ❌ Don't unnecessarily nest fragments
+    let _ = cx.render(rsx!(
+        Fragment {
+            Fragment {
+                Fragment {
+                    Fragment {
+                        Fragment {
+                            div { "Finally have a real node!" }
+                        }
+                    }
+                }
+            }
+        }
+    ));
+
+    // ✅ Render shallow structures
+    cx.render(rsx!(
+        div { "Finally have a real node!" }
+    ))
+    // ANCHOR_END: nested_fragments
+}
+
+#[derive(PartialEq, Props)]
+struct NoKeysProps {
+    data: HashMap<u32, String>,
+}
+
+fn AntipatternNoKeys(cx: Scope<NoKeysProps>) -> Element {
+    // ANCHOR: iter_keys
+    let data: &HashMap<_, _> = &cx.props.data;
+
+    // ❌ No keys
+    cx.render(rsx! {
+        ul {
+            data.values().map(|value| rsx!(
+                li { "List item: {value}" }
+            ))
+        }
+    });
+
+    // ❌ Using index as keys
+    cx.render(rsx! {
+        ul {
+            cx.props.data.values().enumerate().map(|(index, value)| rsx!(
+                li { key: "{index}", "List item: {value}" }
+            ))
+        }
+    });
+
+    // ✅ Using unique IDs as keys:
+    cx.render(rsx! {
+        ul {
+            cx.props.data.iter().map(|(key, value)| rsx!(
+                li { key: "{key}", "List item: {value}" }
+            ))
+        }
+    })
+    // ANCHOR_END: iter_keys
+}

+ 17 - 0
docs/guide/examples/boolean_attribute.rs

@@ -0,0 +1,17 @@
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+fn App(cx: Scope) -> Element {
+    // ANCHOR: boolean_attribute
+    cx.render(rsx! {
+        div {
+            hidden: "false",
+            "hello"
+        }
+    })
+    // ANCHOR_END: boolean_attribute
+}

+ 27 - 0
docs/guide/examples/component_borrowed_props.rs

@@ -0,0 +1,27 @@
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+// ANCHOR: App
+fn App(cx: Scope) -> Element {
+    let hello = "Hello Dioxus!";
+
+    cx.render(rsx!(TitleCard { title: hello }))
+}
+// ANCHOR_END: App
+
+// ANCHOR: TitleCard
+#[derive(Props)]
+struct TitleCardProps<'a> {
+    title: &'a str,
+}
+
+fn TitleCard<'a>(cx: Scope<'a, TitleCardProps<'a>>) -> Element {
+    cx.render(rsx! {
+        h1 { "{cx.props.title}" }
+    })
+}
+// ANCHOR_END: TitleCard

+ 36 - 0
docs/guide/examples/component_children.rs

@@ -0,0 +1,36 @@
+// ANCHOR: all
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+fn App(cx: Scope) -> Element {
+    // ANCHOR: Clickable_usage
+    cx.render(rsx! {
+        Clickable {
+            href: "https://www.youtube.com/watch?v=C-M2hs3sXGo",
+            "How to " i {"not"} " be seen"
+        }
+    })
+    // ANCHOR_END: Clickable_usage
+}
+
+// ANCHOR: Clickable
+#[derive(Props)]
+struct ClickableProps<'a> {
+    href: &'a str,
+    children: Element<'a>,
+}
+
+fn Clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
+    cx.render(rsx!(
+        a {
+            href: "{cx.props.href}",
+            class: "fancy-button",
+            &cx.props.children
+        }
+    ))
+}
+// ANCHOR_END: Clickable

+ 37 - 0
docs/guide/examples/component_children_inspect.rs

@@ -0,0 +1,37 @@
+// ANCHOR: all
+#![allow(non_snake_case, unused)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+fn App(cx: Scope) -> Element {
+    // ANCHOR: Clickable_usage
+    cx.render(rsx! {
+        Clickable {
+            href: "https://www.youtube.com/watch?v=C-M2hs3sXGo",
+            "How to " i {"not"} " be seen"
+        }
+    })
+    // ANCHOR_END: Clickable_usage
+}
+
+#[derive(Props)]
+struct ClickableProps<'a> {
+    href: &'a str,
+    children: Element<'a>,
+}
+
+// ANCHOR: Clickable
+fn Clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
+    match cx.props.children {
+        Some(VNode::Text(_)) => {
+            todo!("render some stuff")
+        }
+        _ => {
+            todo!("render some other stuff")
+        }
+    }
+}
+// ANCHOR_END: Clickable

+ 36 - 0
docs/guide/examples/component_element_props.rs

@@ -0,0 +1,36 @@
+// ANCHOR: all
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+fn App(cx: Scope) -> Element {
+    // ANCHOR: Clickable_usage
+    cx.render(rsx! {
+        Clickable {
+            href: "https://www.youtube.com/watch?v=C-M2hs3sXGo",
+            body: cx.render(rsx!("How to " i {"not"} " be seen")),
+        }
+    })
+    // ANCHOR_END: Clickable_usage
+}
+
+// ANCHOR: Clickable
+#[derive(Props)]
+struct ClickableProps<'a> {
+    href: &'a str,
+    body: Element<'a>,
+}
+
+fn Clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
+    cx.render(rsx!(
+        a {
+            href: "{cx.props.href}",
+            class: "fancy-button",
+            &cx.props.body
+        }
+    ))
+}
+// ANCHOR_END: Clickable

+ 34 - 0
docs/guide/examples/component_owned_props.rs

@@ -0,0 +1,34 @@
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+// ANCHOR: App
+fn App(cx: Scope) -> Element {
+    cx.render(rsx! {
+        Likes {
+            score: 42,
+        },
+    })
+}
+// ANCHOR_END: App
+
+// ANCHOR: Likes
+// Remember: Owned props must implement `PartialEq`!
+#[derive(PartialEq, Props)]
+struct LikesProps {
+    score: i32,
+}
+
+fn Likes(cx: Scope<LikesProps>) -> Element {
+    cx.render(rsx! {
+        div {
+            "This post has ",
+            b { "{cx.props.score}" },
+            " likes"
+        }
+    })
+}
+// ANCHOR_END: Likes

+ 113 - 0
docs/guide/examples/component_props_options.rs

@@ -0,0 +1,113 @@
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+fn App(cx: Scope) -> Element {
+    cx.render(rsx! {
+        // ANCHOR: OptionalProps_usage
+        Title {
+            title: "Some Title",
+        },
+        Title {
+            title: "Some Title",
+            subtitle: "Some Subtitle",
+        },
+        // Providing an Option explicitly won't compile though:
+        // Title {
+        //     title: "Some Title",
+        //     subtitle: None,
+        // },
+        // ANCHOR_END: OptionalProps_usage
+
+        // ANCHOR: ExplicitOption_usage
+        ExplicitOption {
+            title: "Some Title",
+            subtitle: None,
+        },
+        ExplicitOption {
+            title: "Some Title",
+            subtitle: Some("Some Title"),
+        },
+        // This won't compile:
+        // ExplicitOption {
+        //     title: "Some Title",
+        // },
+        // ANCHOR_END: ExplicitOption_usage
+
+        // ANCHOR: DefaultComponent_usage
+        DefaultComponent {
+            number: 5,
+        },
+        DefaultComponent {},
+        // ANCHOR_END: DefaultComponent_usage
+
+        // ANCHOR: IntoComponent_usage
+        IntoComponent {
+            string: "some &str",
+        },
+        // ANCHOR_END: IntoComponent_usage
+    })
+}
+
+// ANCHOR: OptionalProps
+#[derive(Props)]
+struct OptionalProps<'a> {
+    title: &'a str,
+    subtitle: Option<&'a str>,
+}
+
+fn Title<'a>(cx: Scope<'a, OptionalProps>) -> Element<'a> {
+    return cx.render(rsx!(h1{
+        "{cx.props.title}: ",
+        [cx.props.subtitle.unwrap_or("No subtitle provided")],
+    }));
+}
+// ANCHOR_END: OptionalProps
+
+// ANCHOR: ExplicitOption
+#[derive(Props)]
+struct ExplicitOptionProps<'a> {
+    title: &'a str,
+    #[props(!optional)]
+    subtitle: Option<&'a str>,
+}
+
+fn ExplicitOption<'a>(cx: Scope<'a, ExplicitOptionProps>) -> Element<'a> {
+    return cx.render(rsx!(h1{
+        "{cx.props.title}: ",
+        [cx.props.subtitle.unwrap_or("No subtitle provided")],
+    }));
+}
+// ANCHOR_END: ExplicitOption
+
+// ANCHOR: DefaultComponent
+#[derive(PartialEq, Props)]
+struct DefaultProps {
+    // default to 42 when not provided
+    #[props(default = 42)]
+    number: i64,
+}
+
+fn DefaultComponent(cx: Scope<DefaultProps>) -> Element {
+    return cx.render(rsx!(h1{
+        "{cx.props.number}",
+    }));
+}
+// ANCHOR_END: DefaultComponent
+
+// ANCHOR: IntoComponent
+#[derive(PartialEq, Props)]
+struct IntoProps {
+    #[props(into)]
+    string: String,
+}
+
+fn IntoComponent(cx: Scope<IntoProps>) -> Element {
+    return cx.render(rsx!(h1{
+        "{cx.props.string}",
+    }));
+}
+// ANCHOR_END: IntoComponent

+ 24 - 0
docs/guide/examples/components.rs

@@ -0,0 +1,24 @@
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+// ANCHOR: App
+fn App(cx: Scope) -> Element {
+    cx.render(rsx! {
+        About {},
+        About {},
+    })
+}
+// ANCHOR_END: App
+
+// ANCHOR: About
+pub fn About(cx: Scope) -> Element {
+    cx.render(rsx!(p {
+        b {"Dioxus Labs"}
+        " An Open Source project dedicated to making Rust UI wonderful."
+    }))
+}
+// ANCHOR_END: About

+ 60 - 0
docs/guide/examples/conditional_rendering.rs

@@ -0,0 +1,60 @@
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+pub fn App(cx: Scope) -> Element {
+    let is_logged_in = use_state(&cx, || false);
+
+    cx.render(rsx!(LogIn {
+        is_logged_in: **is_logged_in,
+        on_log_in: |_| is_logged_in.set(true),
+        on_log_out: |_| is_logged_in.set(false),
+    }))
+}
+
+#[inline_props]
+fn LogIn<'a>(
+    cx: Scope<'a>,
+    is_logged_in: bool,
+    on_log_in: EventHandler<'a>,
+    on_log_out: EventHandler<'a>,
+) -> Element<'a> {
+    // ANCHOR: if_else
+    if *is_logged_in {
+        cx.render(rsx! {
+            div {
+                "Welcome!",
+                button {
+                    onclick: move |_| on_log_out.call(()),
+                    "Log Out",
+                }
+            }
+        })
+    } else {
+        cx.render(rsx! {
+            button {
+                onclick: move |_| on_log_in.call(()),
+                "Log In",
+            }
+        })
+    }
+    // ANCHOR_END: if_else
+}
+
+#[inline_props]
+fn LogInWarning(cx: Scope, is_logged_in: bool) -> Element {
+    // ANCHOR: conditional_none
+    if *is_logged_in {
+        return None;
+    }
+
+    cx.render(rsx! {
+        a {
+            "You must be logged in to comment"
+        }
+    })
+    // ANCHOR_END: conditional_none
+}

+ 19 - 0
docs/guide/examples/dangerous_inner_html.rs

@@ -0,0 +1,19 @@
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+fn App(cx: Scope) -> Element {
+    // ANCHOR: dangerous_inner_html
+    // this should come from a trusted source
+    let contents = "live <b>dangerously</b>";
+
+    cx.render(rsx! {
+        div {
+            dangerous_inner_html: "{contents}",
+        }
+    })
+    // ANCHOR_END: dangerous_inner_html
+}

+ 17 - 0
docs/guide/examples/event_click.rs

@@ -0,0 +1,17 @@
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+fn App(cx: Scope) -> Element {
+    // ANCHOR: rsx
+    cx.render(rsx! {
+        button {
+            onclick: move |event| println!("Clicked! Event: {event:?}"),
+            "click me!"
+        }
+    })
+    // ANCHOR_END: rsx
+}

+ 33 - 0
docs/guide/examples/event_handler_prop.rs

@@ -0,0 +1,33 @@
+#![allow(non_snake_case)]
+
+use dioxus::events::MouseEvent;
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+fn App(cx: Scope) -> Element {
+    // ANCHOR: usage
+    cx.render(rsx! {
+        FancyButton {
+            on_click: move |event| println!("Clicked! {event:?}")
+        }
+    })
+    // ANCHOR_END: usage
+}
+
+// ANCHOR: component_with_handler
+#[derive(Props)]
+pub struct FancyButtonProps<'a> {
+    on_click: EventHandler<'a, MouseEvent>,
+}
+
+pub fn FancyButton<'a>(cx: Scope<'a, FancyButtonProps<'a>>) -> Element<'a> {
+    cx.render(rsx!(button {
+        class: "fancy-button",
+        onclick: move |evt| cx.props.on_click.call(evt),
+        "click me pls."
+    }))
+}
+// ANCHOR_END: component_with_handler

+ 24 - 0
docs/guide/examples/event_nested.rs

@@ -0,0 +1,24 @@
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+fn App(cx: Scope) -> Element {
+    // ANCHOR: rsx
+    cx.render(rsx! {
+        div {
+            onclick: move |_event| {},
+            "outer",
+            button {
+                onclick: move |event| {
+                    // now, outer won't be triggered
+                    event.cancel_bubble();
+                },
+                "inner"
+            }
+        }
+    })
+    // ANCHOR_END: rsx
+}

+ 17 - 0
docs/guide/examples/event_prevent_default.rs

@@ -0,0 +1,17 @@
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+fn App(cx: Scope) -> Element {
+    // ANCHOR: prevent_default
+    cx.render(rsx! {
+        input {
+            prevent_default: "oninput",
+            prevent_default: "onclick",
+        }
+    })
+    // ANCHOR_END: prevent_default
+}

+ 18 - 0
docs/guide/examples/hello_world_desktop.rs

@@ -0,0 +1,18 @@
+// ANCHOR: all
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+// ANCHOR: component
+fn App(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div {
+            "Hello, world!"
+        }
+    })
+}
+// ANCHOR_END: component
+// ANCHOR_END: all

+ 20 - 0
docs/guide/examples/hello_world_tui.rs

@@ -0,0 +1,20 @@
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::tui::launch(App);
+}
+
+fn App(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div {
+            width: "100%",
+            height: "10px",
+            background_color: "red",
+            justify_content: "center",
+            align_items: "center",
+
+            "Hello world!"
+        }
+    })
+}

+ 36 - 0
docs/guide/examples/hello_world_tui_no_ctrl_c.rs

@@ -0,0 +1,36 @@
+// todo remove deprecated
+#![allow(non_snake_case, deprecated)]
+
+use dioxus::events::{KeyCode, KeyboardEvent};
+use dioxus::prelude::*;
+use dioxus::tui::TuiContext;
+
+fn main() {
+    dioxus::tui::launch_cfg(
+        App,
+        dioxus::tui::Config::new()
+            .without_ctrl_c_quit()
+            // Some older terminals only support 16 colors or ANSI colors
+            // If your terminal is one of these, change this to BaseColors or ANSI
+            .with_rendering_mode(dioxus::tui::RenderingMode::Rgb),
+    );
+}
+
+fn App(cx: Scope) -> Element {
+    let tui_ctx: TuiContext = cx.consume_context().unwrap();
+
+    cx.render(rsx! {
+        div {
+            width: "100%",
+            height: "10px",
+            background_color: "red",
+            justify_content: "center",
+            align_items: "center",
+            onkeydown: move |k: KeyboardEvent| if let KeyCode::Q = k.data.key_code {
+                tui_ctx.quit();
+            },
+
+            "Hello world!"
+        }
+    })
+}

+ 14 - 0
docs/guide/examples/hello_world_web.rs

@@ -0,0 +1,14 @@
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::web::launch(App);
+}
+
+fn App(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div {
+            "Hello, world!"
+        }
+    })
+}

+ 67 - 0
docs/guide/examples/hooks_bad.rs

@@ -0,0 +1,67 @@
+#![allow(non_snake_case)]
+
+use dioxus::prelude::*;
+use std::collections::HashMap;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+fn App(cx: Scope) -> Element {
+    let you_are_happy = true;
+    let you_know_it = false;
+
+    // ANCHOR: conditional
+    // ❌ don't call hooks in conditionals!
+    // We must ensure that the same hooks will be called every time
+    // But `if` statements only run if the conditional is true!
+    // So we might violate rule 2.
+    if you_are_happy && you_know_it {
+        let something = use_state(&cx, || "hands");
+        println!("clap your {something}")
+    }
+
+    // ✅ instead, *always* call use_state
+    // You can put other stuff in the conditional though
+    let something = use_state(&cx, || "hands");
+    if you_are_happy && you_know_it {
+        println!("clap your {something}")
+    }
+    // ANCHOR_END: conditional
+
+    // ANCHOR: closure
+    // ❌ don't call hooks inside closures!
+    // We can't guarantee that the closure, if used, will be called at the same time every time
+    let _a = || {
+        let b = use_state(&cx, || 0);
+        b.get()
+    };
+
+    // ✅ instead, move hook `b` outside
+    let b = use_state(&cx, || 0);
+    let _a = || b.get();
+    // ANCHOR_END: closure
+
+    let names: Vec<&str> = vec![];
+
+    // ANCHOR: loop
+    // `names` is a Vec<&str>
+
+    // ❌ Do not use hooks in loops!
+    // In this case, if the length of the Vec changes, we break rule 2
+    for _name in &names {
+        let is_selected = use_state(&cx, || false);
+        println!("selected: {is_selected}");
+    }
+
+    // ✅ Instead, use a hashmap with use_ref
+    let selection_map = use_ref(&cx, || HashMap::<&str, bool>::new());
+
+    for name in &names {
+        let is_selected = selection_map.read()[name];
+        println!("selected: {is_selected}");
+    }
+    // ANCHOR_END: loop
+
+    None
+}

+ 13 - 0
docs/guide/examples/hooks_composed.rs

@@ -0,0 +1,13 @@
+#![allow(unused)]
+
+use dioxus::prelude::*;
+
+fn main() {}
+
+struct AppSettings {}
+
+// ANCHOR: wrap_context
+fn use_settings(cx: &ScopeState) -> UseSharedState<AppSettings> {
+    use_context::<AppSettings>(&cx).expect("App settings not provided")
+}
+// ANCHOR_END: wrap_context

+ 18 - 0
docs/guide/examples/hooks_counter.rs

@@ -0,0 +1,18 @@
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+// ANCHOR: component
+fn App(cx: Scope) -> Element {
+    let mut count = use_state(&cx, || 0);
+
+    cx.render(rsx!(
+        h1 { "High-Five counter: {count}" }
+        button { onclick: move |_| count += 1, "Up high!" }
+        button { onclick: move |_| count -= 1, "Down low!" }
+    ))
+}
+// ANCHOR_END: component

+ 24 - 0
docs/guide/examples/hooks_counter_two_state.rs

@@ -0,0 +1,24 @@
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+// ANCHOR: component
+fn App(cx: Scope) -> Element {
+    // ANCHOR: use_state_calls
+    let mut count_a = use_state(&cx, || 0);
+    let mut count_b = use_state(&cx, || 0);
+    // ANCHOR_END: use_state_calls
+
+    cx.render(rsx!(
+        h1 { "Counter_a: {count_a}" }
+        button { onclick: move |_| count_a += 1, "a++" }
+        button { onclick: move |_| count_a -= 1, "a--" }
+        h1 { "Counter_b: {count_b}" }
+        button { onclick: move |_| count_b += 1, "b++" }
+        button { onclick: move |_| count_b -= 1, "b--" }
+    ))
+}
+// ANCHOR_END: component

+ 23 - 0
docs/guide/examples/hooks_use_ref.rs

@@ -0,0 +1,23 @@
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+// ANCHOR: component
+fn App(cx: Scope) -> Element {
+    let list = use_ref(&cx, || Vec::new());
+    let list_formatted = format!("{:?}", *list.read());
+
+    cx.render(rsx!(
+        p { "Current list: {list_formatted}" }
+        button {
+            onclick: move |event| {
+                list.write().push(event)
+            },
+            "Click me!"
+        }
+    ))
+}
+// ANCHOR_END: component

+ 21 - 0
docs/guide/examples/input_controlled.rs

@@ -0,0 +1,21 @@
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+// ANCHOR: component
+fn App(cx: Scope) -> Element {
+    let name = use_state(&cx, || "bob".to_string());
+
+    cx.render(rsx! {
+        input {
+            // we tell the component what to render
+            value: "{name}",
+            // and what to do when the value changes
+            oninput: move |evt| name.set(evt.value.clone()),
+        }
+    })
+}
+// ANCHOR_END: component

+ 22 - 0
docs/guide/examples/input_uncontrolled.rs

@@ -0,0 +1,22 @@
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+// ANCHOR: component
+fn App(cx: Scope) -> Element {
+    cx.render(rsx! {
+        form {
+            onsubmit: move |event| {
+                println!("Submitted! {event:?}")
+            },
+            input { name: "name", },
+            input { name: "age", },
+            input { name: "date", },
+            input { r#type: "submit", },
+        }
+    })
+}
+// ANCHOR_END: component

+ 105 - 0
docs/guide/examples/meme_editor.rs

@@ -0,0 +1,105 @@
+// ANCHOR: all
+#![allow(non_snake_case)]
+
+use dioxus::events::FormEvent;
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(MemeEditor);
+}
+
+// ANCHOR: meme_editor
+fn MemeEditor(cx: Scope) -> Element {
+    let container_style = r"
+        display: flex;
+        flex-direction: column;
+        gap: 16px;
+        margin: 0 auto;
+        width: fit-content;
+    ";
+
+    let caption = use_state(&cx, || "me waiting for my rust code to compile".to_string());
+
+    cx.render(rsx! {
+        div {
+            style: "{container_style}",
+            h1 { "Meme Editor" },
+            Meme {
+                caption: caption,
+            },
+            CaptionEditor {
+                caption: caption,
+                on_input: move |event: FormEvent| {caption.set(event.value.clone());},
+            },
+        }
+    })
+}
+// ANCHOR_END: meme_editor
+
+// ANCHOR: meme_component
+#[inline_props]
+fn Meme<'a>(cx: Scope<'a>, caption: &'a str) -> Element<'a> {
+    let container_style = r#"
+        position: relative;
+        width: fit-content;
+    "#;
+
+    let caption_container_style = r#"
+        position: absolute;
+        bottom: 0;
+        left: 0;
+        right: 0;
+        padding: 16px 8px;
+    "#;
+
+    let caption_style = r"
+        font-size: 32px;
+        margin: 0;
+        color: white;
+        text-align: center;
+    ";
+
+    cx.render(rsx!(
+        div {
+            style: "{container_style}",
+            img {
+                src: "https://i.imgflip.com/2zh47r.jpg",
+                height: "500px",
+            },
+            div {
+                style: "{caption_container_style}",
+                p {
+                    style: "{caption_style}",
+                    "{caption}"
+                }
+            }
+        }
+    ))
+}
+// ANCHOR_END: meme_component
+
+// ANCHOR: caption_editor
+#[inline_props]
+fn CaptionEditor<'a>(
+    cx: Scope<'a>,
+    caption: &'a str,
+    on_input: EventHandler<'a, FormEvent>,
+) -> Element<'a> {
+    let input_style = r"
+        border: none;
+        background: cornflowerblue;
+        padding: 8px 16px;
+        margin: 0;
+        border-radius: 4px;
+        color: white;
+    ";
+
+    cx.render(rsx!(input {
+        style: "{input_style}",
+        value: "{caption}",
+        oninput: move |event| on_input.call(event),
+    }))
+}
+// ANCHOR_END: caption_editor
+
+// ANCHOR_END: all

+ 184 - 0
docs/guide/examples/meme_editor_dark_mode.rs

@@ -0,0 +1,184 @@
+// ANCHOR: all
+#![allow(non_snake_case)]
+
+use dioxus::events::FormEvent;
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+// ANCHOR: DarkMode_struct
+struct DarkMode(bool);
+// ANCHOR_END: DarkMode_struct
+
+pub fn App(cx: Scope) -> Element {
+    // ANCHOR: context_provider
+    use_context_provider(&cx, || DarkMode(false));
+    // ANCHOR_END: context_provider
+
+    let is_dark_mode = use_is_dark_mode(&cx);
+
+    let wrapper_style = if is_dark_mode {
+        r"
+            background: #222;
+            min-height: 100vh;
+        "
+    } else {
+        r""
+    };
+
+    cx.render(rsx!(div {
+        style: "{wrapper_style}",
+        DarkModeToggle {},
+        MemeEditor {},
+    }))
+}
+
+pub fn use_is_dark_mode(cx: &ScopeState) -> bool {
+    // ANCHOR: use_context
+    let dark_mode_context = use_context::<DarkMode>(&cx);
+    // ANCHOR_END: use_context
+
+    dark_mode_context
+        .map(|context| context.read().0)
+        .unwrap_or(false)
+}
+
+// ANCHOR: toggle
+pub fn DarkModeToggle(cx: Scope) -> Element {
+    let dark_mode = use_context::<DarkMode>(&cx)?;
+
+    let style = if dark_mode.read().0 {
+        "color:white"
+    } else {
+        ""
+    };
+
+    cx.render(rsx!(label {
+        style: "{style}",
+        "Dark Mode",
+        input {
+            r#type: "checkbox",
+            oninput: move |event| {
+                let is_enabled = event.value == "true";
+                dark_mode.write().0 = is_enabled;
+            },
+        },
+    }))
+}
+// ANCHOR_END: toggle
+
+// ANCHOR: meme_editor
+fn MemeEditor(cx: Scope) -> Element {
+    let is_dark_mode = use_is_dark_mode(&cx);
+    let heading_style = if is_dark_mode { "color: white" } else { "" };
+
+    let container_style = r"
+        display: flex;
+        flex-direction: column;
+        gap: 16px;
+        margin: 0 auto;
+        width: fit-content;
+    ";
+
+    let caption = use_state(&cx, || "me waiting for my rust code to compile".to_string());
+
+    cx.render(rsx! {
+        div {
+            style: "{container_style}",
+            h1 {
+                style: "{heading_style}",
+                "Meme Editor"
+            },
+            Meme {
+                caption: caption,
+            },
+            CaptionEditor {
+                caption: caption,
+                on_input: move |event: FormEvent| {caption.set(event.value.clone());},
+            },
+        }
+    })
+}
+// ANCHOR_END: meme_editor
+
+// ANCHOR: meme_component
+#[inline_props]
+fn Meme<'a>(cx: Scope<'a>, caption: &'a str) -> Element<'a> {
+    let container_style = r"
+        position: relative;
+        width: fit-content;
+    ";
+
+    let caption_container_style = r"
+        position: absolute;
+        bottom: 0;
+        left: 0;
+        right: 0;
+        padding: 16px 8px;
+    ";
+
+    let caption_style = r"
+        font-size: 32px;
+        margin: 0;
+        color: white;
+        text-align: center;
+    ";
+
+    cx.render(rsx!(
+        div {
+            style: "{container_style}",
+            img {
+                src: "https://i.imgflip.com/2zh47r.jpg",
+                height: "500px",
+            },
+            div {
+                style: "{caption_container_style}",
+                p {
+                    style: "{caption_style}",
+                    "{caption}"
+                }
+            }
+        }
+    ))
+}
+// ANCHOR_END: meme_component
+
+// ANCHOR: caption_editor
+#[inline_props]
+fn CaptionEditor<'a>(
+    cx: Scope<'a>,
+    caption: &'a str,
+    on_input: EventHandler<'a, FormEvent>,
+) -> Element<'a> {
+    let is_dark_mode = use_is_dark_mode(&cx);
+
+    let colors = if is_dark_mode {
+        r"
+            background: cornflowerblue;
+            color: white;
+        "
+    } else {
+        r"
+            background: #def;
+            color: black;
+        "
+    };
+
+    let input_style = r"
+        border: none;
+        padding: 8px 16px;
+        margin: 0;
+        border-radius: 4px;
+    ";
+
+    cx.render(rsx!(input {
+        style: "{input_style}{colors}",
+        value: "{caption}",
+        oninput: move |event| on_input.call(event),
+    }))
+}
+// ANCHOR_END: caption_editor
+
+// ANCHOR_END: all

+ 60 - 0
docs/guide/examples/rendering_lists.rs

@@ -0,0 +1,60 @@
+#![allow(non_snake_case)]
+
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+#[derive(PartialEq, Clone)]
+struct Comment {
+    content: String,
+    id: usize,
+}
+
+pub fn App(cx: Scope) -> Element {
+    // ANCHOR: render_list
+    let comment_field = use_state(&cx, || String::new());
+    let mut next_id = use_state(&cx, || 0);
+    let comments = use_ref(&cx, || Vec::<Comment>::new());
+
+    let comments_lock = comments.read();
+    let comments_rendered = comments_lock.iter().map(|comment| {
+        cx.render(rsx!(CommentComponent {
+            key: "{comment.id}",
+            comment: comment.clone(),
+        }))
+    });
+
+    cx.render(rsx!(
+        form {
+            onsubmit: move |_| {
+                comments.write().push(Comment {
+                    content: comment_field.get().clone(),
+                    id: *next_id.get(),
+                });
+                next_id += 1;
+
+                comment_field.set(String::new());
+            },
+            input {
+                value: "{comment_field}",
+                oninput: |event| comment_field.set(event.value.clone()),
+            }
+            input {
+                r#type: "submit",
+            }
+        },
+        comments_rendered,
+    ))
+    // ANCHOR_END: render_list
+}
+
+#[inline_props]
+fn CommentComponent(cx: Scope, comment: Comment) -> Element {
+    cx.render(rsx!(div {
+        "Comment by anon:",
+        p { "{comment.content}" }
+        button { "Reply" },
+    }))
+}

+ 109 - 0
docs/guide/examples/rsx_overview.rs

@@ -0,0 +1,109 @@
+#![allow(non_snake_case)]
+
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+pub fn App(cx: Scope) -> Element {
+    cx.render(rsx!(
+        Empty {},
+        Children {},
+        Fragments {},
+        Attributes {},
+        VariableAttributes {},
+        CustomAttributes {},
+        Formatting {},
+        Expression {},
+    ))
+}
+
+pub fn Empty(cx: Scope) -> Element {
+    // ANCHOR: empty
+    cx.render(rsx!(div {}))
+    // ANCHOR_END: empty
+}
+
+pub fn Children(cx: Scope) -> Element {
+    // ANCHOR: children
+    cx.render(rsx!(ol {
+        li {"First Item"}
+        li {"Second Item"}
+        li {"Third Item"}
+    }))
+    // ANCHOR_END: children
+}
+
+pub fn Fragments(cx: Scope) -> Element {
+    // ANCHOR: fragments
+    cx.render(rsx!(
+        p {"First Item"},
+        p {"Second Item"},
+        Fragment {
+            span { "a group" },
+            span { "of three" },
+            span { "items" },
+        }
+    ))
+    // ANCHOR_END: fragments
+}
+
+pub fn Attributes(cx: Scope) -> Element {
+    // ANCHOR: attributes
+    cx.render(rsx!(a {
+        href: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
+        class: "primary_button",
+        "Log In"
+    }))
+    // ANCHOR_END: attributes
+}
+
+pub fn VariableAttributes(cx: Scope) -> Element {
+    // ANCHOR: variable_attributes
+    let written_in_rust = true;
+    let button_type = "button";
+    cx.render(rsx!(button {
+        disabled: "{written_in_rust}",
+        class: "{button_type}",
+        "Rewrite it in rust"
+    }))
+    // ANCHOR_END: variable_attributes
+}
+
+pub fn CustomAttributes(cx: Scope) -> Element {
+    // ANCHOR: custom_attributes
+    cx.render(rsx!(b {
+        "customAttribute": "value",
+        "Rust is Cool"
+    }))
+    // ANCHOR_END: custom_attributes
+}
+
+pub fn Formatting(cx: Scope) -> Element {
+    // ANCHOR: formatting
+    let coordinates = (42, 0);
+    let country = "es";
+    cx.render(rsx!(div {
+        class: "country-{country}",
+        "Coordinates: {coordinates:?}",
+        // arbitrary expressions are allowed,
+        // as long as they don't contain `{}`
+        div {
+            "{country.to_uppercase()}"
+        },
+        div {
+            "{7*6}"
+        },
+    }))
+    // ANCHOR_END: formatting
+}
+
+pub fn Expression(cx: Scope) -> Element {
+    // ANCHOR: expression
+    let text = "Dioxus";
+    cx.render(rsx!(span {
+        [text.to_uppercase()]
+    }))
+    // ANCHOR_END: expression
+}

+ 84 - 0
docs/guide/examples/spawn.rs

@@ -0,0 +1,84 @@
+#![allow(non_snake_case, unused)]
+
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+fn App(cx: Scope) -> Element {
+    // ANCHOR: spawn
+    let logged_in = use_state(&cx, || false);
+
+    let log_in = move |_| {
+        cx.spawn({
+            let logged_in = logged_in.to_owned();
+
+            async move {
+                let resp = reqwest::Client::new()
+                    .post("http://example.com/login")
+                    .send()
+                    .await;
+
+                match resp {
+                    Ok(_data) => {
+                        println!("Login successful!");
+                        logged_in.set(true);
+                    }
+                    Err(_err) => {
+                        println!(
+                            "Login failed - you need a login server running on localhost:8080."
+                        )
+                    }
+                }
+            }
+        });
+    };
+
+    cx.render(rsx! {
+        button {
+            onclick: log_in,
+            "Login",
+        }
+    })
+    // ANCHOR_END: spawn
+}
+
+pub fn Tokio(cx: Scope) -> Element {
+    let _ = || {
+        // ANCHOR: tokio
+        cx.spawn(async {
+            let _ = tokio::spawn(async {}).await;
+
+            let _ = tokio::task::spawn_local(async {
+                // some !Send work
+            })
+            .await;
+        });
+        // ANCHOR_END: tokio
+    };
+
+    None
+}
+
+pub fn ToOwnedMacro(cx: Scope) -> Element {
+    let count = use_state(&cx, || 0);
+    let age = use_state(&cx, || 0);
+    let name = use_state(&cx, || 0);
+    let description = use_state(&cx, || 0);
+
+    let _ = || {
+        // ANCHOR: to_owned_macro
+        use dioxus::core::to_owned;
+
+        cx.spawn({
+            to_owned![count, age, name, description];
+            async move {
+                // ...
+            }
+        });
+        // ANCHOR_END: to_owned_macro
+    };
+
+    None
+}

+ 60 - 0
docs/guide/examples/use_future.rs

@@ -0,0 +1,60 @@
+#![allow(non_snake_case, unused)]
+
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+#[derive(serde::Deserialize, Debug)]
+struct ApiResponse {
+    #[serde(rename = "message")]
+    image_url: String,
+}
+
+fn App(cx: Scope) -> Element {
+    // ANCHOR: use_future
+    let future = use_future(&cx, (), |_| async move {
+        reqwest::get("https://dog.ceo/api/breeds/image/random")
+            .await
+            .unwrap()
+            .json::<ApiResponse>()
+            .await
+    });
+    // ANCHOR_END: use_future
+
+    // ANCHOR: render
+    cx.render(match future.value() {
+        Some(Ok(response)) => rsx! {
+            button {
+                onclick: move |_| future.restart(),
+                "Click to fetch another doggo"
+            }
+            div {
+                img {
+                    max_width: "500px",
+                    max_height: "500px",
+                    src: "{response.image_url}",
+                }
+            }
+        },
+        Some(Err(_)) => rsx! { div { "Loading dogs failed" } },
+        None => rsx! { div { "Loading dogs..." } },
+    })
+    // ANCHOR_END: render
+}
+
+#[inline_props]
+fn RandomDog(cx: Scope, breed: String) -> Element {
+    // ANCHOR: dependency
+    let future = use_future(&cx, (breed,), |(breed,)| async move {
+        reqwest::get(format!("https://dog.ceo/api/breed/{breed}/images/random"))
+            .await
+            .unwrap()
+            .json::<ApiResponse>()
+            .await
+    });
+    // ANCHOR_END: dependency
+
+    None
+}

+ 0 - 105
docs/guide/src/README.md

@@ -1,105 +0,0 @@
-# Introduction
-
-![dioxuslogo](./images/dioxuslogo_full.png)
-
-**Dioxus** is a library for building fast, scalable, and robust user interfaces with the Rust programming language. This guide will help you get started with Dioxus running on the Web, Desktop, Mobile, and more.
-
-```rust
-fn app(cx: Scope) -> Element {
-    let mut count = use_state(&cx, || 0);
-
-    cx.render(rsx!(
-        h1 { "High-Five counter: {count}" }
-        button { onclick: move |_| count += 1, "Up high!" }
-        button { onclick: move |_| count -= 1, "Down low!" }
-    ))
-};
-```
-
-In general, Dioxus and React share many functional similarities. If this guide is lacking in any general concept or an error message is confusing, React's documentation might be more helpful. We are dedicated to providing a *familiar* toolkit for UI in Rust, so we've chosen to follow in the footsteps of popular UI frameworks (React, Redux, etc). If you know React, then you already know Dioxus. If you don't know either, this guide will still help you!
-
-> This is an introduction book! For advanced topics, check out the [Reference](/reference) instead.
-
-## Multiplatform
-
-Dioxus is a *portable* toolkit, meaning the Core implementation can run anywhere with no platform-dependent linking. Unlike many other Rust frontend toolkits, Dioxus is not intrinsically linked to WebSys. In fact, every element and event listener can be swapped out at compile time. By default, Dioxus ships with the `html` feature enabled, but this can be disabled depending on your target renderer.
-
-Right now, we have several 1st-party renderers:
-- WebSys (for WASM)
-- Tao/Tokio (for Desktop apps)
-- Tao/Tokio (for Mobile apps)
-- SSR (for generating static markup)
-- TUI/Rink (for terminal-based apps)
-
-### Web Support
----
-The Web is the best-supported target platform for Dioxus. To run on the Web, your app must be compiled to WebAssembly and depend on the `dioxus` crate with the `web` feature enabled. Because of the limitations of Wasm  not every crate will work with your web-apps, so you'll need to make sure that your crates work without native system calls (timers, IO, etc).
-
-Because the web is a fairly mature platform, we expect there to be very little API churn for web-based features.
-
-[Jump to the getting started guide for the web.](/reference/platforms/web)
-
-Examples:
-- [TodoMVC](https://github.com/DioxusLabs/example-projects/tree/master/todomvc)
-- [ECommerce](https://github.com/DioxusLabs/example-projects/tree/master/ecommerce-site)
-
-[![TodoMVC example](https://github.com/DioxusLabs/example-projects/raw/master/todomvc/example.png)](https://github.com/DioxusLabs/example-projects/blob/master/todomvc)
-
-### SSR Support
----
-Dioxus supports server-side rendering!
-
-For rendering statically to an `.html` file or from a WebServer, then you'll want to make sure the `ssr` feature is enabled in the `dioxus` crate and use the `dioxus::ssr` API. We don't expect the SSR API to change drastically in the future.
-
-```rust
-let contents = dioxus::ssr::render_vdom(&dom);
-```
-
-[Jump to the getting started guide for SSR.](/reference/platforms/ssr)
-
-Examples:
-- [Example DocSite](https://github.com/dioxusLabs/docsite)
-- [Tide WebServer]()
-- [Markdown to fancy HTML generator]()
-
-### Desktop Support
----
-The desktop is a powerful target for Dioxus, but is currently limited in capability when compared to the Web platform. Currently, desktop apps are rendered with the platform's WebView library, but your Rust code is running natively on a native thread. This means that browser APIs are *not* available, so rendering WebGL, Canvas, etc is not as easy as the Web. However, native system APIs *are* accessible, so streaming, WebSockets, filesystem, etc are all viable APIs. In the future, we plan to move to a custom webrenderer-based DOM renderer with WGPU integrations.
-
-Desktop APIs will likely be in flux as we figure out better patterns than our ElectronJS counterpart.
-
-[Jump to the getting started guide for Desktop.](/reference/platforms/desktop)
-
-Examples:
-- [File explorer](https://github.com/DioxusLabs/example-projects/blob/master/file-explorer)
-- [WiFi scanner](https://github.com/DioxusLabs/example-projects/blob/master/wifi-scanner)
-
-[![File ExplorerExample](https://raw.githubusercontent.com/DioxusLabs/example-projects/master/file-explorer/image.png)](https://github.com/DioxusLabs/example-projects/tree/master/file-explorer)
-
-### Mobile Support
----
-Mobile is currently the least-supported renderer target for Dioxus. Mobile apps are rendered with the platform's WebView, meaning that animations, transparency, and native widgets are not currently achievable. In addition, iOS is the only supported Mobile Platform. It is possible to get Dioxus running on Android and rendered with WebView, but the Rust windowing library that Dioxus uses - tao - does not currently supported Android.
-
-Mobile support is currently best suited for CRUD-style apps, ideally for internal teams who need to develop quickly but don't care much about animations or native widgets.
-
-[Jump to the getting started guide for Mobile.](/reference/platforms/mobile)
-
-Examples:
-- [Todo App](https://github.com/DioxusLabs/example-projects/blob/master/ios_demo)
-
-### LiveView / Server Component Support
----
-
-The internal architecture of Dioxus was designed from day one to support the `LiveView` use-case, where a web server hosts a running app for each connected user. As of today, there is no first-class LiveView support - you'll need to wire this up yourself.
-
-While not currently fully implemented, the expectation is that LiveView apps can be a hybrid between Wasm and server-rendered where only portions of a page are "live" and the rest of the page is either server-rendered, statically generated, or handled by the host SPA.
-
-### Multithreaded Support
----
-The Dioxus VirtualDom, sadly, is not currently `Send`. Internally, we use quite a bit of interior mutability which is not thread-safe. This means you can't easily use Dioxus with most web frameworks like Tide, Rocket, Axum, etc.
-
-To solve this, you'll want to spawn a VirtualDom on its own thread and communicate with it via channels.
-
-When working with web frameworks that require `Send`, it is possible to render a VirtualDom immediately to a String - but you cannot hold the VirtualDom across an await point. For retained-state SSR (essentially LiveView), you'll need to create a pool of VirtualDoms.
-
-Ultimately, you can always wrap the VirtualDom with a `Send` type and manually uphold the `Send` guarantees yourself.

+ 33 - 44
docs/guide/src/SUMMARY.md

@@ -1,54 +1,43 @@
 # Summary
 
-- [Introduction](README.md)
-- [Roadmap](ROADMAP.md)
-- [Getting Set Up](setup.md)
-- [Hello, World!](hello_world.md)
-- [Describing the UI](elements/index.md)
-  - [Intro to Elements](elements/vnodes.md)
-  - [Conditional Rendering](elements/conditional_rendering.md)
-  - [Lists](elements/lists.md)
-  - [Special Attributes](elements/special_attributes.md)
-- [Components](components/index.md)
-  - [Properties](components/propsmacro.md)
-  - [Reusing, Importing, and Exporting](components/exporting_components.md)
-  - [Children and Attributes](components/component_children.md)
-  - [How Data Flows](components/composing.md)
-- [Adding Interactivity](interactivity/index.md)
+[Introduction](index.md)
+
+- [Getting Started](getting_started/index.md)
+  - [Desktop](getting_started/desktop.md)
+  - [Web](getting_started/web.md)
+    - [Hot Reload](getting_started/hot_reload.md)
+  - [Server-Side Rendering](getting_started/ssr.md)
+  - [Terminal UI](getting_started/tui.md)
+  - [Mobile](getting_started/mobile.md)
+- [Describing the UI](describing_ui/index.md)
+  - [Special Attributes](describing_ui/special_attributes.md)
+  - [Components](describing_ui/components.md)
+  - [Props](describing_ui/component_props.md)
+  - [Component Children](describing_ui/component_children.md)
+- [Interactivity](interactivity/index.md)
   - [Event Listeners](interactivity/event_handlers.md)
-  - [Hooks](interactivity/hooks.md)
-  - [UseState](interactivity/usestate.md)
-  - [UseRef](interactivity/useref.md)
+  - [Hooks & Component State](interactivity/hooks.md)
   - [User Input](interactivity/user_input.md)
-  <!-- - [Effects](interactivity/lifecycles.md) -->
-- [Managing State](state/index.md)
-  - [Local State](state/localstate.md)
-  - [Global State](state/sharedstate.md)
-  - [Lifting State](state/liftingstate.md)
-  - [Error handling](state/errorhandling.md)
-- [Helper Crates](helpers/index.md)
-  - [Fermi](state/fermi.md)
-  - [Router](state/router.md)
-- [Working with Async](async/index.md)
+  - [Sharing State](interactivity/sharing_state.md)
+  - [Custom Hooks](interactivity/custom_hooks.md)
+  - [Dynamic Rendering](interactivity/dynamic_rendering.md)
+  - [Routing](interactivity/router.md)
+- [Async](async/index.md)
   - [UseFuture](async/use_future.md)
-  - [UseCoroutine](async/coroutines.md)
-  - [Updating State](async/loading_state.md)
-  - [Tasks](async/asynctasks.md)
-
-<!--
-- [Putting it all together: Dog Search Engine](tutorial/index.md)
-  - [New app](tutorial/new_app.md)
-  - [Bundling](tutorial/publishing.md) -->
-
-
-- [Next Steps and Advanced Topics](final.md)
-
+  - [UseCoroutine](async/use_coroutine.md)
+  - [Spawning Futures](async/spawn.md)
+- [Best Practices](best_practices/index.md)
+  - [Error Handling](best_practices/error_handling.md)
+  - [Antipatterns](best_practices/antipatterns.md)
+- [Publishing](publishing/index.md)
+  - [Desktop](publishing/desktop.md)
+  - [Web](publishing/web.md)
 
 -----------
 
-[Contributors](misc/contributors.md)
-
+- [Custom Renderer](custom_renderer/index.md)
 
-  <!-- - [Suspense](concepts/suspense.md) -->
-  <!-- - [Async Callbacks](concepts/asynccallbacks.md) -->
+-----------
 
+[Roadmap](roadmap.md)
+[Contributing](contributing.md)

+ 6 - 0
docs/guide/src/__unused/README.md

@@ -0,0 +1,6 @@
+This directory includes:
+
+- Very outdated docs
+- Docs for features which haven't been implemented (yet?)
+- Information which has already been covered in the guide in a more organized fashion
+- A few things yet to be integrated into the guide nicely

+ 0 - 0
docs/guide/src/advanced-guides/06-subscription-api.md → docs/guide/src/__unused/advanced-guides/06-subscription-api.md


+ 0 - 0
docs/guide/src/advanced-guides/10-concurrent-mode.md → docs/guide/src/__unused/advanced-guides/10-concurrent-mode.md


+ 2 - 2
docs/guide/src/advanced-guides/11-arena-memo.md → docs/guide/src/__unused/advanced-guides/11-arena-memo.md

@@ -2,9 +2,9 @@
 
 Dioxus differs slightly from other UI virtual doms in some subtle ways due to its memory allocator.
 
-One important aspect to understand is how props are passed down from parent components to children. All "components" (custom user-made UI elements) are tightly allocated together in an arena. However, because props and hooks are generically typed, they are casted to `Any` and allocated on the heap - not in the arena with the components.
+One important aspect to understand is how props are passed down from parent components to children. All "components" (custom user-made UI elements) are tightly allocated together in an arena. However, because props and hooks are generically typed, they are casted to `Any` and allocated on the heap  not in the arena with the components.
 
-With this system, we try to be more efficient when leaving the component arena and entering the heap. By default, props are memoized between renders using COW and context. This makes props comparisons fast - done via ptr comparisons on the cow pointer. Because memoization is done by default, parent re-renders will _not_ cascade to children if the child's props did not change.
+With this system, we try to be more efficient when leaving the component arena and entering the heap. By default, props are memoized between renders using COW and context. This makes props comparisons fast  done via ptr comparisons on the cow pointer. Because memoization is done by default, parent re-renders will _not_ cascade to children if the child's props did not change.
 
 https://dmitripavlutin.com/use-react-memo-wisely/
 

+ 3 - 3
docs/guide/src/advanced-guides/12-signals.md → docs/guide/src/__unused/advanced-guides/12-signals.md

@@ -22,7 +22,7 @@ fn Comp(cx: Scope) -> DomTree {
 }
 ```
 
-This component is fairly straightforward - the input updates its own value on every change. However, every call to set_title will re-render the component. If we add a large list, then every time we update the title input, Dioxus will need to diff the entire list, over, and over, and over. This is **a lot** of wasted clock-cycles!
+This component is fairly straightforward  the input updates its own value on every change. However, every call to set_title will re-render the component. If we add a large list, then every time we update the title input, Dioxus will need to diff the entire list, over, and over, and over. This is **a lot** of wasted clock-cycles!
 
 ```rust
 fn Comp(cx: Scope) -> DomTree {
@@ -43,7 +43,7 @@ fn Comp(cx: Scope) -> DomTree {
 }
 ```
 
-Many experienced React developers will just say "this is bad design" - but we consider it to be a pit of failure, rather than a pit of success! That's why signals exist - to push you in a more performant (and ergonomic) direction. Signals let us directly bind values to their final place in the VirtualDOM. Whenever the signal value is updated, Dioxus will only the DOM nodes where that signal is used. Signals are built into Dioxus, so we can directly bind attributes of elements to their updates.
+Many experienced React developers will just say "this is bad design" – but we consider it to be a pit of failure, rather than a pit of success! That's why signals exist – to push you in a more performant (and ergonomic) direction. Signals let us directly bind values to their final place in the VirtualDOM. Whenever the signal value is updated, Dioxus will only the DOM nodes where that signal is used. Signals are built into Dioxus, so we can directly bind attributes of elements to their updates.
 
 We can use signals to generate a two-way binding between data and the input box. Our text input is now just a two-line component!
 
@@ -124,7 +124,7 @@ If you build a complex app on top of Dirac, you'll likely notice that many of yo
 
 ## Signals and Iterators
 
-Sometimes you want to use a collection of items. With Signals, you can bypass diffing for collections - a very powerful technique to avoid re-rendering on large collections.
+Sometimes you want to use a collection of items. With Signals, you can bypass diffing for collections  a very powerful technique to avoid re-rendering on large collections.
 
 By default, Dioxus is limited when you use iter/map. With the `For` component, you can provide an iterator and a function for the iterator to map to.
 

+ 2 - 2
docs/guide/src/advanced-guides/13-subtrees.md → docs/guide/src/__unused/advanced-guides/13-subtrees.md

@@ -16,7 +16,7 @@ Root
 
 The goal of this functionality is to enable things like Portals, Windows, and inline alternative renderers without needing to spin up a new VirtualDom.
 
-With the right renderer plugins, a subtree could be rendered as anything - a 3D scene, SVG, or even as the contents of a new window or modal. This functionality is similar to "Portals" in React, but much more "renderer agnostic." Portals, by nature, are not necessarily cross-platform and rely on renderer functionality, so it makes sense to abstract their purpose into the subtree concept.
+With the right renderer plugins, a subtree could be rendered as anything  a 3D scene, SVG, or even as the contents of a new window or modal. This functionality is similar to "Portals" in React, but much more "renderer agnostic." Portals, by nature, are not necessarily cross-platform and rely on renderer functionality, so it makes sense to abstract their purpose into the subtree concept.
 
 The desktop renderer comes pre-loaded with the window and notification subtree plugins, making it possible to render subtrees into entirely different windows.
 
@@ -25,7 +25,7 @@ Subtrees also solve the "bridging" issues in React where two different renderers
 
 ## API
 
-Due to their importance in the hierarchy, Components - not nodes - are treated as subtree roots.
+Due to their importance in the hierarchy, Components – not nodes – are treated as subtree roots.
 
 
 ```rust

+ 3 - 3
docs/guide/src/advanced-guides/custom-renderer.md → docs/guide/src/__unused/advanced-guides/custom-renderer.md

@@ -54,7 +54,7 @@ The Dioxus diffing mechanism operates as a [stack machine](https://en.wikipedia.
 
 ### An example
 
-For the sake of understanding, lets consider this example - a very simple UI declaration:
+For the sake of understanding, lets consider this example  a very simple UI declaration:
 
 ```rust
 rsx!( h1 {"hello world"} )
@@ -218,7 +218,7 @@ fn virtual_event_from_websys_event(event: &web_sys::Event) -> VirtualEvent {
 
 ## Custom raw elements
 
-If you need to go as far as relying on custom elements for your renderer - you totally can. This still enables you to use Dioxus' reactive nature, component system, shared state, and other features, but will ultimately generate different nodes. All attributes and listeners for the HTML and SVG namespace are shuttled through helper structs that essentially compile away (pose no runtime overhead). You can drop in your own elements any time you want, with little hassle. However, you must be absolutely sure your renderer can handle the new type, or it will crash and burn.
+If you need to go as far as relying on custom elements for your renderer  you totally can. This still enables you to use Dioxus' reactive nature, component system, shared state, and other features, but will ultimately generate different nodes. All attributes and listeners for the HTML and SVG namespace are shuttled through helper structs that essentially compile away (pose no runtime overhead). You can drop in your own elements any time you want, with little hassle. However, you must be absolutely sure your renderer can handle the new type, or it will crash and burn.
 
 These custom elements are defined as unit structs with trait implementations.
 
@@ -248,7 +248,7 @@ There are three opportunities for platform incompatibilities to break your progr
 2. When downcasting events via `Event.downcast_ref<T>()`
 3. Calling platform-specific APIs that don't exist
 
-The best hooks will properly detect the target platform and still provide functionality, failing gracefully when a platform is not supported. We encourage - and provide - an indication to the user on what platforms a hook supports. For issues 1 and 2, these return a result as to not cause panics on unsupported platforms. When designing your hooks, we recommend propagating this error upwards into user facing code, making it obvious that this particular service is not supported.
+The best hooks will properly detect the target platform and still provide functionality, failing gracefully when a platform is not supported. We encourage – and provide – an indication to the user on what platforms a hook supports. For issues 1 and 2, these return a result as to not cause panics on unsupported platforms. When designing your hooks, we recommend propagating this error upwards into user facing code, making it obvious that this particular service is not supported.
 
 This particular code _will panic_ due to the unwrap on downcast_ref. Try to avoid these types of patterns.
 

+ 1 - 1
docs/guide/src/advanced-guides/liveview.md → docs/guide/src/__unused/advanced-guides/liveview.md

@@ -11,7 +11,7 @@ Because Liveview combines the server and the client, you'll find dedicated APIs
 You can find more information to data modeling and fetching for LiveApps in the "Book of Dioxus Patterns".
 
 ### Ease of deployment
-There is no hassle for deploying Dioxus liveview apps - simply upload the binary to your hosting provider of choice. There simply is no need to deal with intermediate APIs. An app's frontend and backend are tightly coupled to each other, meaning that the backed and frontend are always up to date.
+There is no hassle for deploying Dioxus liveview apps  simply upload the binary to your hosting provider of choice. There simply is no need to deal with intermediate APIs. An app's frontend and backend are tightly coupled to each other, meaning that the backed and frontend are always up to date.
 
 This is especially powerful for small teams, where fast iteration, versioned unique prototypes, and simple deployments are important. As your app grows, Dioxus will happily grow with you, serving up to 100K RPS (thanks to async Rust performance).
 

+ 3 - 3
docs/guide/src/advanced-guides/rsx.md → docs/guide/src/__unused/advanced-guides/rsx.md

@@ -2,7 +2,7 @@
 
 Many modern frameworks provide a domain-specific-language for declaring user-interfaces. In the case of React, this language extension is called JSX and must be handled through additional dependencies and pre/post processors to transform your source code. With Rust, we can simply provide a procedural macro in the Dioxus dependency itself that mimics the JSX language.
 
-With Dioxus, we actually ship two different macros - a macro that mimics JSX (the `html!` macro) and a macro that mimics Rust's native nested-struct syntax (the `rsx!` macro). These macros simply transform their inputs into NodeFactory calls.
+With Dioxus, we actually ship two different macros  a macro that mimics JSX (the `html!` macro) and a macro that mimics Rust's native nested-struct syntax (the `rsx!` macro). These macros simply transform their inputs into NodeFactory calls.
 
 For instance, this html! call:
 ```rust
@@ -18,7 +18,7 @@ becomes this NodeFactory call:
     None // key
 )
 ```
-The NodeFactory API is fairly ergonomic, making it a viable option to use directly. The NodeFactory API is also compile-time correct and has incredible syntax highlighting support. We use what Rust calls a "unit type" - the `dioxus_elements::div` and associated methods to ensure that a `div` can only have attributes associated with `div`s. This lets us tack on relevant documentation, autocomplete support, and jump-to-definition for methods and attributes.
+The NodeFactory API is fairly ergonomic, making it a viable option to use directly. The NodeFactory API is also compile-time correct and has incredible syntax highlighting support. We use what Rust calls a "unit type"  the `dioxus_elements::div` and associated methods to ensure that a `div` can only have attributes associated with `div`s. This lets us tack on relevant documentation, autocomplete support, and jump-to-definition for methods and attributes.
 
 ![Compile time correct syntax](../images/compiletimecorrect.png)
 
@@ -26,7 +26,7 @@ The NodeFactory API is fairly ergonomic, making it a viable option to use direct
 
 The html! macro supports a limited subset of the html standard. Rust's macro parsing tools are somewhat limited, so all text between tags _must be quoted_.
 
-However, writing HTML by hand is a bit tedious - IDE tools for Rust don't support linting/autocomplete/syntax highlighting. We suggest using RSX - it's more natural for Rust programs and _does_ integrate well with Rust IDE tools.
+However, writing HTML by hand is a bit tedious – IDE tools for Rust don't support linting/autocomplete/syntax highlighting. We suggest using RSX – it's more natural for Rust programs and _does_ integrate well with Rust IDE tools.
 
 ```rust
 let name = "jane";

+ 1 - 1
docs/guide/src/advanced-guides/testing.md → docs/guide/src/__unused/advanced-guides/testing.md

@@ -21,7 +21,7 @@ fn runs_in_browser() {
 Then, when you run
 
 ```console
-$ dioxus test --chrome
+dioxus test --chrome
 ```
 
 Dioxus will build and test your code using the Chrome browser as a harness.

+ 29 - 0
docs/guide/src/__unused/attribute_spreading.md

@@ -0,0 +1,29 @@
+In the cases where you need to pass arbitrary element properties into a component – say to add more functionality to the `<a>` tag, Dioxus will accept any quoted fields. This is similar to adding arbitrary fields to regular elements using quotes.
+
+```rust
+
+rsx!(
+    Clickable {
+        "class": "blue-button",
+        "style": "background: red;"
+    }
+)
+
+```
+
+For a component to accept these attributes, you must add an `attributes` field to your component's properties. We can use the spread syntax to add these attributes to whatever nodes are in our component.
+
+```rust
+#[derive(Props)]
+struct ClickableProps<'a> {
+    attributes: Attributes<'a>
+}
+
+fn clickable(cx: Scope<ClickableProps<'a>>) -> Element {
+    cx.render(rsx!(
+        a {
+            ..cx.props.attributes,
+            "Any link, anywhere"
+        }
+    ))
+}

+ 1 - 1
docs/guide/src/components/composing.md → docs/guide/src/__unused/composing.md

@@ -15,7 +15,7 @@ This section is a bit long, but worth the read. We recommend coffee, tea, and/or
 
 ## Reactive Programming
 
-Dioxus is one of a handful of Rust libraries that provide a "Reactive Programming Model". The term "Reactive programming" is a classification of programming paradigm - much like functional or imperative programming. This is a very important distinction since it affects how we *think* about our code.
+Dioxus is one of a handful of Rust libraries that provide a "Reactive Programming Model". The term "Reactive programming" is a classification of programming paradigm  much like functional or imperative programming. This is a very important distinction since it affects how we *think* about our code.
 
 Reactive programming is a programming model concerned with deriving computations from asynchronous data flow. Most reactive programs are comprised of datasources, intermediate computations, and a final result.
 

+ 26 - 0
docs/guide/src/__unused/event_javascript.rs

@@ -0,0 +1,26 @@
+
+## JavaScript Handlers
+
+Instead of passing a closure, you can also pass a string to event handlers – this lets you use JavaScript (if your renderer can execute JavaScript):
+
+```rust
+{{#include ../../examples/event_javascript.rs:rsx}}
+```
+
+
+#![allow(non_snake_case)]
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(App);
+}
+
+fn App(cx: Scope) -> Element {
+    cx.render(rsx! {
+        // ANCHOR: rsx
+        div {
+            onclick: "alert('hello world')",
+        }
+        // ANCHOR_END: rsx
+    })
+}

+ 2 - 2
docs/guide/src/state/fanout.md → docs/guide/src/__unused/fanout.md

@@ -35,7 +35,7 @@ fn Titlebar(cx: Scope<TitlebarProps>) -> Element {
 }
 ```
 
-For many apps - this is a fine pattern, especially if the component is a one-off. However, if we want to reuse the component outside of this app, then we'll start to run into issues where our contexts are unavailable.
+For many apps  this is a fine pattern, especially if the component is a one-off. However, if we want to reuse the component outside of this app, then we'll start to run into issues where our contexts are unavailable.
 
 ## Fanning Out
 
@@ -58,4 +58,4 @@ fn DocsiteTitlesection(cx: Scope) {
 
 This particular wrapper component unfortunately cannot be reused across apps. However, because it simply wraps other real elements, it doesn't have to. We are free to reuse our TitleBar and UserBar components across apps with ease. We also know that this particular component is plenty performant because the wrapper doesn't have any props and is always memoized. The only times this component re-renders is when any of the atoms change.
 
-This is the beauty of Dioxus - we always know where our components are likely to be re-rendered. Our wrapper components can easily prevent any large re-renders by simply memoizing their components. This system might not be as elegant or precise as signal systems found in libraries like Sycamore or SolidJS, but it is quite ergonomic.
+This is the beauty of Dioxus  we always know where our components are likely to be re-rendered. Our wrapper components can easily prevent any large re-renders by simply memoizing their components. This system might not be as elegant or precise as signal systems found in libraries like Sycamore or SolidJS, but it is quite ergonomic.

+ 14 - 0
docs/guide/src/__unused/hello_world.md

@@ -0,0 +1,14 @@
+# "Hello, World" desktop app
+
+
+
+If you plan to develop extensions for the `Dioxus` ecosystem, please use the `dioxus` crate with the `core` feature to limit the amount of dependencies your project brings in.
+
+
+### What is this `Scope` object?
+
+Coming from React, the `Scope` object might be confusing. In React, you'll want to store data between renders with hooks. However, hooks rely on global variables which make them difficult to integrate in multi-tenant systems like server-rendering.
+
+In Dioxus, you are given an explicit `Scope` object to control how the component renders and stores data. The `Scope` object provides a handful of useful APIs for features like suspense, rendering, and more.
+
+For now, just know that `Scope` lets you store state with hooks and render elements with `cx.render`.

+ 4 - 4
docs/guide/src/helpers/index.md → docs/guide/src/__unused/helpers.md

@@ -18,27 +18,27 @@ Global state as easy as `use_state`.
 
 This crate has yet to be developed! However, we do plan on providing a crate for good fetching and query support.
 
-## 3rd-party - Toast
+## 3rd-party  Toast
 
 Toast notifications, curtesy of [@mrxiaozhuox](https://github.com/mrxiaozhuox).
 
 [Link](https://github.com/mrxiaozhuox/dioxus-toast)
 
-## 3rd-party - HeroIcon
+## 3rd-party  HeroIcon
 
 Collection of helpful hero icons, curtesy of [@autarch](https://github.com/autarch).
 
 
 [Link](https://github.com/houseabsolute/dioxus-heroicons)
 
-## 3rd-party - Katex
+## 3rd-party  Katex
 
 Draw beautiful equations, curtesy of [@oovm](https://github.com/oovm)
 
 [Link](https://github.com/oovm/katex-wasm/tree/dev/projects/dioxus-katex)
 
 
-## 3rd-party - PrimsJS
+## 3rd-party  PrimsJS
 
 Highlight your code blocks with ease, curtesy of [@oovm](https://github.com/oovm)
 

+ 3 - 3
docs/guide/src/state/index.md → docs/guide/src/__unused/index.md

@@ -9,9 +9,9 @@ In this chapter, we'll cover the various ways to manage state, the appropriate t
 
 Why do people say state management is so difficult? What does it mean?
 
-Generally, state management is the code you need to write to ensure that your app renders the *correct* content. If the user inputs a name, then you need to display the appropriate response - like alerts, validation, and disable/enable various elements on the page. Things can quickly become tricky if you need loading screens and cancellable tasks.
+Generally, state management is the code you need to write to ensure that your app renders the *correct* content. If the user inputs a name, then you need to display the appropriate response  like alerts, validation, and disable/enable various elements on the page. Things can quickly become tricky if you need loading screens and cancellable tasks.
 
-For the simplest of apps, all of your state can enter the app from the root props. This is common in server-side rendering - we can collect all of the required state *before* rendering the content.
+For the simplest of apps, all of your state can enter the app from the root props. This is common in server-side rendering  we can collect all of the required state *before* rendering the content.
 
 ```rust
 let all_content = get_all_content().await;
@@ -25,7 +25,7 @@ let output = dioxus::ssr::render_lazy(rsx!{
 
 With this incredibly simple setup, it is highly unlikely that you'll have rendering bugs. There simply is barely any state to manage.
 
-However, most of your apps will store state inside of the Dioxus VirtualDom - either through local state or global state.
+However, most of your apps will store state inside of the Dioxus VirtualDom  either through local state or global state.
 
 
 ## Your options

+ 3 - 3
docs/guide/src/state/localstate.md → docs/guide/src/__unused/localstate.md

@@ -59,14 +59,14 @@ struct Todo {
 }
 ```
 
-This is not only better for encapsulation and abstraction, but it's only more performant! Whenever a Todo is hovered, we won't need to re-render *every* Todo again - only the Todo that's currently being hovered.
+This is not only better for encapsulation and abstraction, but it's only more performant! Whenever a Todo is hovered, we won't need to re-render *every* Todo again  only the Todo that's currently being hovered.
 
 
 Wherever possible, you should try to refactor the "view" layer *out* of your data model.
 
 ## Immutability
 
-Storing all of your state inside a `use_ref` might be tempting. However, you'll quickly run into an issue where the `Ref` provided by `read()` "does not live long enough." An indeed - you can't return locally-borrowed value into the Dioxus tree.
+Storing all of your state inside a `use_ref` might be tempting. However, you'll quickly run into an issue where the `Ref` provided by `read()` "does not live long enough." An indeed  you can't return locally-borrowed value into the Dioxus tree.
 
 In these scenarios consider breaking your `use_ref` into individual `use_state`s.
 
@@ -91,7 +91,7 @@ let color = use_state(&cx, || "red");
 let names = use_state(&cx, HashMap::new);
 ```
 
-You might recognize that our "names" value is a HashMap - which is not terribly cheap to clone every time we update its value. To solve this issue, we *highly* suggest using a library like [`im`](https://crates.io/crates/im) which will take advantage of structural sharing to make clones and mutations much cheaper.
+You might recognize that our "names" value is a HashMap  which is not terribly cheap to clone every time we update its value. To solve this issue, we *highly* suggest using a library like [`im`](https://crates.io/crates/im) which will take advantage of structural sharing to make clones and mutations much cheaper.
 
 When combined with the `make_mut` method on `use_state`, you can get really succinct updates to collections:
 

+ 28 - 0
docs/guide/src/__unused/memoization.md

@@ -0,0 +1,28 @@
+
+## Memoization
+
+Dioxus uses Memoization for a more efficient user interface. Memoization is the process in which we check if a component actually needs to be re-rendered when its props change. If a component's properties change but they wouldn't affect the output, then we don't need to re-render the component, saving time!
+
+For example, let's say we have a component that has two children:
+
+```rust
+fn Demo(cx: Scope) -> Element {
+    // don't worry about these 2, we'll cover them later
+    let name = use_state(&cx, || String::from("bob"));
+    let age = use_state(&cx, || 21);
+
+    cx.render(rsx!{
+        Name { name: name }
+        Age { age: age }
+    })
+}
+```
+
+If `name` changes but `age` does not, then there is no reason to re-render our `Age` component since the contents of its props did not meaningfully change.
+
+Dioxus memoizes owned components. It uses `PartialEq` to determine if a component needs rerendering, or if it has stayed the same. This is why you must derive PartialEq!
+
+> This means you can always rely on props with `PartialEq` or no props at all to act as barriers in your app. This can be extremely useful when building larger apps where properties frequently change. By moving our state into a global state management solution, we can achieve precise, surgical re-renders, improving the performance of our app.
+
+Borrowed Props cannot be safely memoized. However, this is not a problem – Dioxus relies on the memoization of their parents to determine if they need to be rerendered.
+

+ 67 - 0
docs/guide/src/__unused/model_pattern.md

@@ -0,0 +1,67 @@
+
+
+## Using UseRef with "models"
+
+One option for state management that UseRef enables is the development of a "model" for your components. This particular pattern enables you to model your state with regular structs.
+
+For instance, our calculator example uses a struct to model the state.
+
+```rust
+
+struct Calculator {
+    display_value: String,
+    operator: Option<Operator>,
+    waiting_for_operand: bool,
+    cur_val: f64,
+}
+```
+
+Our component is really simple – we just call `use_ref` to get an initial calculator state.
+
+```rust
+fn app(cx: Scope) -> Element {
+    let state = use_ref(&cx, Calculator::new);
+
+    cx.render(rsx!{
+        // the rendering code
+    })
+}
+```
+
+In our UI, we can then use `read` and a helper method to get data out of the model.
+
+```rust
+// Our accessor method
+impl Calculator {
+    fn formatted_display(&self) -> String {
+        self.display_value
+            .parse::<f64>()
+            .unwrap()
+            .separated_string()
+    }
+}
+
+// And then in the UI
+cx.render(rsx!{
+    div { [state.read().formatted_display()] }
+})
+```
+
+To modify the state, we can setup a helper method and then attach it to a callback.
+
+```rust
+// our helper
+impl Calculator {
+    fn clear_display(&mut self) {
+        self.display_value = "0".to_string()
+    }
+}
+
+// our callback
+cx.render(rsx!{
+    button {
+        onclick: move |_| state.write().clear_display(),
+    }
+})
+```
+

+ 0 - 73
docs/guide/src/advanced-guides/00-index.md

@@ -1,73 +0,0 @@
-# Core Topics
-
-In this chapter, we'll cover some core topics about how Dioxus works and how to best leverage the features to build a beautiful, reactive app.
-
-At a very high level, Dioxus is simply a Rust framework for _declaring_ user interfaces and _reacting_ to changes.
-
-1) We declare what we want our user interface to look like given a state using Rust-based logic and control flow.
-2) We declare how we want our state to change when the user triggers an event.
-
-## Declarative UI
-
-Dioxus is a *declarative* framework. This means that instead of manually writing calls to "create element" and "set element background to red," we simply *declare* what we want the element to look like and let Dioxus handle the differences.
-
-Let's pretend that we have a stoplight we need to control - it has a color state with red, yellow, and green as options.
-
-
-Using an imperative approach, we would have to manually declare each element and then handlers for advancing the stoplight.
-
-```rust
-let container = Container::new();
-
-let green_light = Light::new().color("green").enabled(true);
-let yellow_light = Light::new().color("yellow").enabled(false);
-let red_light = Light::new().color("red").enabled(false);
-container.push(green_light);
-container.push(yellow_light);
-container.push(red_light);
-
-container.set_onclick(move |_| {
-    if red_light.enabled() {
-        red_light.set_enabled(false);
-        green_light.set_enabled(true);
-    } else if yellow_light.enabled() {
-        yellow_light.set_enabled(false);
-        red_light.set_enabled(true);
-    } else if green_light.enabled() {
-        green_light.set_enabled(false);
-        yellow_light.set_enabled(true);
-    }
-});
-```
-
-As the UI grows in scale, our logic to keep each element in the proper state would grow exponentially. This can become very unwieldy and lead to out-of-sync UIs that harm user experience.
-
-Instead, with Dioxus, we *declare* what we want our UI to look like:
-
-```rust
-let mut state = use_state(&cx, || "red");
-
-cx.render(rsx!(
-    Container {
-        Light { color: "red", enabled: state == "red", }
-        Light { color: "yellow", enabled: state == "yellow", }
-        Light { color: "green", enabled: state == "green", }
-
-        onclick: move |_| {
-            state.set(match *state {
-                "green" => "yellow",
-                "yellow" => "red",
-                "red" => "green",
-            })
-        }
-    }
-))
-```
-
-Remember: this concept is not new! Many frameworks are declarative - with React being the most popular. Declarative frameworks tend to be much more enjoyable to work with than imperative frameworks.
-
-Here's some reading about declaring UI in React:
-
-- [https://stackoverflow.com/questions/33655534/difference-between-declarative-and-imperative-in-react-js](https://stackoverflow.com/questions/33655534/difference-between-declarative-and-imperative-in-react-js)
-
-- [https://medium.com/@myung.kim287/declarative-vs-imperative-251ce99c6c44](https://medium.com/@myung.kim287/declarative-vs-imperative-251ce99c6c44)

+ 0 - 229
docs/guide/src/advanced-guides/rsx_in_depth.md

@@ -1,229 +0,0 @@
-# RSX in Depth
-
-The RSX macro makes it very easy to assemble complex UIs with a very natural Rust syntax:
-
-
-```rust
-rsx!(div {
-    button {
-        "Add todo",
-        onclick: move |e| todos.write().new_todo()
-    }
-    ul {
-        class: "todo-list"
-        (todos.iter().map(|(key, todo)| rsx!(
-            li { 
-                class: "beautiful-todo"
-                key: "f"
-                h3 { "{todo.title}" }
-                p { "{todo.contents}"}
-            }
-        )))
-    }
-})
-```
-
-In this section, we'll cover the `rsx!` macro in depth. If you prefer to learn through examples, the `reference` guide has plenty of examples on how to use `rsx!` effectively.
-
-
-
-### Element structure
-
-```rust
-div {
-    hidden: false,
-    "some text"
-    child {}
-    Component {}
-    {/* literal tokens that resolve to vnodes */}
-}
-
-```
-
-Each element takes a comma-separated list of expressions to build the node. Roughly, here's how they work:
-
-- `name: value` sets a property on this element.
-- `"text"` adds a new text element
-- `tag {}` adds a new child element
-- `CustomTag {}` adds a new child component
-- `{expr}` pastes the `expr` tokens literally. They must be `IntoIterator<T> where T: IntoVnode` to work properly
-
-Commas are entirely optional, but might be useful to delineate between elements and attributes.
-
-The `render` function provides an **extremely efficient** allocator for VNodes and text, so try not to use the `format!` macro in your components. Rust's default `ToString` methods pass through the global allocator, but all text in components is allocated inside a manually-managed Bump arena. To push you in the right direction, all text-based attributes take `std::fmt::Arguments` directly, so you'll want to reach for `format_args!` when the built-in `f-string` interpolation just doesn't cut it.
-
-
-### Ignoring `cx.render` with `rsx!(cx, ...)`
-
-Sometimes, writing `cx.render` is a hassle. The `rsx! macro will accept any token followed by a comma as the target to call "render" on:
-
-```rust
-cx.render(rsx!( div {} ))
-// becomes
-rsx!(cx, div {})
-```
-
-
-
-### Conditional Rendering
-
-Sometimes, you might not want to render an element given a condition. The rsx! macro will accept any tokens directly contained with curly braces, provided they resolve to a type that implements `IntoIterator<VNode>`. This lets us write any Rust expression that resolves to a VNode:
-
-
-```rust
-rsx!({
-    if enabled {
-        rsx!(cx, div {"enabled"})
-    } else {
-        rsx!(cx, li {"disabled"})
-    }
-})
-```
-A convenient way of hiding/showing an element is returning an `Option<VNode>`. When combined with `and_then`, we can succinctly control the display state given some boolean:
-
-```rust
-rsx!({
-    a.and_then(rsx!(div {"enabled"}))
-})
-```
-
-It's important to note that the expression `rsx!()` is typically lazy - this expression must be _rendered_ to produce a VNode. When using match statements, we must render every arm as to avoid the `no two closures are identical` rule that Rust imposes:
-
-```rust
-// this will not compile!
-match case {
-    true => rsx!(div {}),
-    false => rsx!(div {})
-}
-
-// the nodes must be rendered first
-match case {
-    true => rsx!(cx, div {}),
-    false => rsx!(cx, div {})
-}
-```
-
-### Lists
-
-Again, because anything that implements `IntoIterator<VNode>` is valid, we can use lists directly in our `rsx!`:
-
-```rust
-let items = vec!["a", "b", "c"];
-
-cx.render(rsx!{
-    ul {
-        {items.iter().map(|f| rsx!(li { "a" }))}
-    }
-})
-```
-
-Sometimes, it makes sense to render VNodes into a list:
-
-```rust
-let mut items = vec![];
-
-for _ in 0..5 {
-    items.push(rsx!(cx, li {} ))
-}
-
-rsx!(cx, {items} )
-```
-
-#### Lists and Keys
-
-When rendering the VirtualDom to the screen, Dioxus needs to know which elements have been added and which have been removed. These changes are determined through a process called "diffing" - an old set of elements is compared to a new set of elements. If an element is removed, then it won't show up in the new elements, and Dioxus knows to remove it.
-
-However, with lists, Dioxus does not exactly know how to determine which elements have been added or removed if the order changes or if an element is added or removed from the middle of the list.
-
-In these cases, it is vitally important to specify a "key" alongside the element. Keys should be persistent between renders.
-
-```rust
-fn render_list(cx: Scope, items: HashMap<String, Todo>) -> DomTree {
-    rsx!(cx, ul {
-        {items.iter().map(|key, item| {
-            li {
-                key: key,
-                h2 { "{todo.title}" }
-                p { "{todo.contents}" }
-            }
-        })}
-    })
-}
-```
-
-There have been many guides made for keys in React, so we recommend reading up to understand their importance:
-
-- [React guide on keys](https://reactjs.org/docs/lists-and-keys.html)
-- [Importance of keys (Medium)](https://kentcdodds.com/blog/understanding-reacts-key-prop)
-
-### Complete Reference
-```rust
-let text = "example";
-
-cx.render(rsx!{
-    div {
-        h1 { "Example" },
-
-        {title}
-
-        // fstring interpolation
-        "{text}"
-
-        p {
-            // Attributes
-            tag: "type",
-
-            // Anything that implements display can be an attribute
-            abc: 123,
-            
-            enabled: true,
-
-            // attributes also supports interpolation
-            // `class` is not a restricted keyword unlike JS and ClassName
-            class: "big small wide short {text}",
-
-            class: format_args!("attributes take fmt::Arguments. {}", 99),
-
-            tag: {"these tokens are placed directly"}
-
-            // Children
-            a { "abcder" },
-
-            // Children with attributes
-            h2 { "hello", class: "abc-123" },
-
-            // Child components
-            CustomComponent { a: 123, b: 456, key: "1" },
-
-            // Child components with paths
-            crate::components::CustomComponent { a: 123, b: 456, key: "1" },
-
-            // Iterators
-            { (0..3).map(|i| rsx!( h1 {"{:i}"} )) },
-
-            // More rsx!, or even html!
-            { rsx! { div { } } },
-            { html! { <div> </div> } },
-
-            // Matching
-            // Requires rendering the nodes first.
-            // rsx! is lazy, and the underlying closures cannot have the same type
-            // Rendering produces the VNode type
-            {match rand::gen_range::<i32>(1..3) {
-                1 => rsx!(cx, h1 { "big" })
-                2 => rsx!(cx, h2 { "medium" })
-                _ => rsx!(cx, h3 { "small" })
-            }}
-
-            // Optionals
-            {true.and_then(|f| rsx!( h1 {"Conditional Rendering"} ))}
-
-            // Child nodes
-            {cx.props.children}
-
-            // Any expression that is `IntoVNode`
-            {expr}
-        }
-    }
-})
-```

+ 0 - 90
docs/guide/src/async/asynctasks.md

@@ -1,90 +0,0 @@
-# Tasks
-
-All async code in Dioxus must be explicit and handled through Dioxus' task system.
-
-In this chapter, we'll learn how to spawn new tasks through our `Scope`.
-
-## Spawning a task
-
-You can push any `'static` future into the Dioxus future queue by simply calling `cx.spawn` to spawn a task. Pushing a future returns a `TaskId` which can then be used to cancel the 
-
-```rust
-fn App(cx: Scope) -> Element {
-    cx.spawn(async {
-        let mut count = 0;
-        loop {
-            tokio::time::delay(std::instant::Duration::from_millis(500)).await;
-            count += 1;
-            println!("Current count is {}", count);
-        }
-    });
-
-    None
-}
-```
-
-The future must be `'static` - so any values captured by the task must not carry any references to `cx`. All the Dioxus hooks have a method called `for_async` which will create a slightly more limited handle to the hook for you to use in your async code.
-
-```rust
-fn App(cx: Scope) -> Element {
-    let mut count = use_state(&cx, || 0);
-
-    let taskid = cx.spawn({
-        let mut count = count.for_async();
-        async {
-            loop {
-                tokio::time::delay(std::instant::Duration::from_millis(500)).await;
-                count += 1;
-                println!("Current count is {}", count);
-            }
-        }
-    });
-}
-```
-
-The task will run in the background until it is completed.
-
-> Note: `spawn` will always spawn a *new* future. You probably want to call it from a hook initializer instead of the main body of your component.
-
-When bringing lots of values into your task, we provide the `for_async!` macro which will can `for_async` on all values passed in. For types that implement `ToOwned`, `for_async!` will simply call `ToOwned` for that value.
-
-```rust
-fn App(cx: Scope) -> Element {
-    let mut age = use_state(&cx, || 0);
-    let mut name = use_state(&cx, || "Bob");
-    let mut description = use_state(&cx, || "asd".to_string());
-
-    let taskid = cx.spawn({
-        for_async![count, name, description]
-        async { /* code that uses count/name/description */ }
-    });
-}
-```
-
-## Details of Tasks
-
-Calling `spawn` is *not* a hook and will *always* generate a new task. Make sure to only spawn tasks when you want to. You should *probably* not call `spawn` in the main body of your component, since a new task will be spawned on every render.
-
-## Spawning Tokio Tasks (for multithreaded use cases)
-
-Sometimes, you might want to spawn a background task that needs multiple threads or talk to hardware that might block your app code. In these cases, we can can directly spawn a `tokio task` from our future. For Dioxus-Desktop, your task will be spawned onto Tokio's Multithreaded runtime:
-
-```rust
-cx.spawn({
-    tokio::spawn(async {
-        // some multithreaded work
-    }).await;
-
-    tokio::spawn_blocking(|| {
-        // some extremely blocking work
-    }).await;
-
-    tokio::spawn_local(|| {
-        // some !Send work
-    }).await;
-})
-```
-
-> Note: Tokio tasks must be `Send`. Most hooks are `Send` compatible, but if they aren't, then you can use `spawn_local` to spawn onto Dioxus-Desktop's `localset`.
-
-

+ 2 - 97
docs/guide/src/async/index.md

@@ -1,104 +1,9 @@
 # Working with Async
 
-Not all apps you'll build can be self-contained with synchronous code. You'll often need to interact with file systems, network interfaces, hardware, or timers.
-
-So far, we've only talked about building apps with synchronous code, so this chapter will focus integrating asynchronous code into your app.
+Often, apps need to interact with file systems, network interfaces, hardware, or timers. This chapter provides an overview of using async code in Dioxus.
 
 ## The Runtime
 
 By default, Dioxus-Desktop ships with the `Tokio` runtime and automatically sets everything up for you. This is currently not configurable, though it would be easy to write an integration for Dioxus desktop that uses a different asynchronous runtime.
 
-## Send/Sync
-Writing apps that deal with Send/Sync can be frustrating at times. Under the hood, Dioxus is not currently thread-safe, so any async code you write does *not* need to be `Send/Sync`. That means that you can use non-thread-safe structures like `Cell`, `Rc`, and `RefCell`.
-
-All async code in your app is polled on a `LocalSet`, so you can also use `tokio::spawn_local`.
-
-## Spawning a future
-
-Currently, all futures in Dioxus must be `'static`. To spawn a future, simply call `cx.spawn()`.
-
-```rust
-rsx!{
-    button {
-        onclick: move |_| cx.spawn(async move {
-            let result = fetch_thing().await;
-        })
-    }
-}
-```
-
-Calling `spawn` will give you a `JoinHandle` which lets you cancel or pause the future.
-
-
-## Setting state from within a future
-
-If you start to write some async code, you'll quickly be greeted with the infamous error about borrowed items in static closures.
-
-```
-error[E0759]: `cx` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> examples/tasks.rs:13:27
-   |
-12 | fn app(cx: Scope) -> Element {
-   |            ----- this data with an anonymous lifetime `'_`...
-13 |     let count = use_state(&cx, || 0);
-   |                           ^^^ ...is used here...
-14 |
-15 |     use_future(&cx, (), move |_| {
-   |     ---------- ...and is required to live as long as `'static` here
-   |
-note: `'static` lifetime requirement introduced by this bound
-  --> /Users/jonkelley/Development/dioxus/packages/hooks/src/usefuture.rs:25:29
-   |
-25 |     F: Future<Output = T> + 'static,
-   |                             ^^^^^^^
-
-For more information about this error, try `rustc --explain E0759`.
-error: could not compile `dioxus` due to previous error
-```
-
-Rustc tends to provide great feedback in its errors, but this particular error is actually quite unhelpful. For reference, here's our code:
-
-```rust
-fn app(cx: Scope) -> Element {
-    let count = use_state(&cx, || 0);
-
-    cx.spawn(async move {
-        tokio::time::sleep(Duration::from_millis(1000)).await;
-        count += 1;
-    });
-
-    cx.render(rsx! {
-        button {
-            onclick: move |_| count.set(0),
-            "Reset the count"
-        }
-    })
-}
-```
-
-Simple, right? We spawn a future that updates the value after one second has passed. Well, yes, and no. Our `count` value is only valid for the lifetime of this component, but our future could still be running even after the component re-renders. By default, Dioxus places a requirement on all futures to be `'static`, meaning they can't just borrow state from our hooks outright.
-
-To get around this, we need to get a `'static` handle to our state. All Dioxus hooks implement `Clone`, so you simply need to call clone before spawning your future. Any time you get the particular error above, make sure you call `Clone` or `ToOwned`.
-
-```rust
-cx.spawn({
-    let mut count = count.clone();
-    async move {
-        tokio::time::sleep(Duration::from_millis(1000)).await;
-        count += 1;
-    }
-});
-```
-
-To make this a little bit easier, Dioxus exports the `to_owned!` macro which will create a binding as shown above, which can be quite helpful when dealing with many values.
-
-```rust
-cx.spawn({
-    to_owned![count, age, name, description, etc];
-    async move {
-        tokio::time::sleep(Duration::from_millis(1000)).await;
-        count += 1;
-    }
-});
-```
-
+Dioxus is not currently thread-safe, so any async code you write does *not* need to be `Send/Sync`. That means that you can use non-thread-safe structures like `Cell`, `Rc`, and `RefCell`.

+ 0 - 8
docs/guide/src/async/loading_state.md

@@ -1,8 +0,0 @@
-# Updating State
-
-After your future has been spawned, you might want to update the state of our UI. Possible implementations might include:
-
-- A loading state
-- A transition state
-- Showing failures
-- Listening to sockets and updating the app

+ 29 - 0
docs/guide/src/async/spawn.md

@@ -0,0 +1,29 @@
+# Spawning Futures
+
+The `use_future` and `use_coroutine` hooks are useful if you want to unconditionally spawn the future. Sometimes, though, you'll want to only spawn a future in response to an event, such as a mouse click. For example, suppose you need to send a request when the user clicks a "log in" button. For this, you can use `cx.spawn`:
+
+```rust
+{{#include ../../examples/spawn.rs:spawn}}
+```
+
+> Note: `spawn` will always spawn a *new* future. You most likely don't want to call it on every render.
+
+The future must be `'static` – so any values captured by the task cannot carry any references to `cx`, such as a `UseState`.
+
+However, since you'll typically need a way to update the value of a hook, you can use `to_owned` to create a clone of the hook handle. You can then use that clone in the async closure.
+
+To make this a bit less verbose, Dioxus exports the `to_owned!` macro which will create a binding as shown above, which can be quite helpful when dealing with many values.
+
+```rust
+{{#include ../../examples/spawn.rs:to_owned_macro}}
+```
+
+Calling `spawn` will give you a `JoinHandle` which lets you cancel or pause the future.
+
+## Spawning Tokio Tasks
+
+Sometimes, you might want to spawn a background task that needs multiple threads or talk to hardware that might block your app code. In these cases, we can directly spawn a Tokio task from our future. For Dioxus-Desktop, your task will be spawned onto Tokio's Multithreaded runtime:
+
+```rust
+{{#include ../../examples/spawn.rs:tokio}}
+```

+ 2 - 2
docs/guide/src/async/coroutines.md → docs/guide/src/async/use_coroutine.md

@@ -48,7 +48,7 @@ if sync.is_running() {
 }
 ```
 
-This pattern is where coroutines are extremely useful - instead of writing all the complicated logic for pausing our async tasks like we would with JavaScript promises, the Rust model allows us to just not poll our future.
+This pattern is where coroutines are extremely useful  instead of writing all the complicated logic for pausing our async tasks like we would with JavaScript promises, the Rust model allows us to just not poll our future.
 
 ## Sending Values
 
@@ -103,7 +103,7 @@ async fn editor_service(rx: UnboundedReceiver<EditorCommand>) {
 }
 ```
 
-We can combine coroutines with Fermi to emulate Redux Toolkit's Thunk system with much less headache. This lets us store all of our app's state *within* a task and then simply update the "view" values stored in Atoms. It cannot be understated how powerful this technique is: we get all the perks of native Rust tasks with the optimizations and ergonomics of global state. This means your *actual* state does not need to be tied up in a system like Fermi or Redux - the only Atoms that need to exist are those that are used to drive the display/UI.
+We can combine coroutines with Fermi to emulate Redux Toolkit's Thunk system with much less headache. This lets us store all of our app's state *within* a task and then simply update the "view" values stored in Atoms. It cannot be understated how powerful this technique is: we get all the perks of native Rust tasks with the optimizations and ergonomics of global state. This means your *actual* state does not need to be tied up in a system like Fermi or Redux  the only Atoms that need to exist are those that are used to drive the display/UI.
 
 ```rust
 static USERNAME: Atom<String> = |_| "default".to_string();

+ 14 - 66
docs/guide/src/async/use_future.md

@@ -1,85 +1,33 @@
 # UseFuture
 
-When dealing with asynchronous code, you might need to wait for some action to complete before rendering your component. If you had to build this abstraction yourself, you'd probably end up with some `use_state` spaghetti code.
+[`use_future`](https://docs.rs/dioxus-hooks/latest/dioxus_hooks/fn.use_future.html) lets you run an async closure, and provides you with its result.
 
-One of the core hooks that Dioxus provides is `use_future` - a simple hook that lets you tap into a running task.
-
-## Use case
-
-The simplest use case of `use_future` is to prevent rendering until some asynchronous code has been completed. Dioxus doesn't currently have a library as sophisticated as React Query for prefetching tasks, but we can get some of the way there with `use_future`. In one of the Dioxus examples, we use `use_future` to download some search data before rendering the rest of the app:
+For example, we can make an API request inside `use_future`:
 
 ```rust
-fn app(cx: Scope) -> Element {
-    // set "breeds" to the current value of the future
-    let breeds = use_future(&cx, (), |_| async move {
-        reqwest::get("https://dog.ceo/api/breeds/list/all")
-            .await
-            .unwrap()
-            .json::<ListBreeds>()
-            .await
-    });
-
-    let status = match breeds.value() {
-        Some(Ok(val)) => "ready!",
-        Some(Err(err)) => "errored!",
-        None => "loading!",
-    }
-}
+{{#include ../../examples/use_future.rs:use_future}}
 ```
 
-On first run, the code inside `use_future` will be submitted to the Dioxus scheduler once the component has rendered. Since there's no data ready when the component loads the first time, its "value" will be `None`.
+The code inside `use_future` will be submitted to the Dioxus scheduler once the component has rendered.
 
-However, once the future is finished, the component will be re-rendered and a new screen will be displayed - Ok or Err, depending on the outcome of our fetch.
+We can use `.value()` to get the result of the future. On the first run, since there's no data ready when the component loads, its value will be `None`.  However, once the future is finished, the component will be re-rendered and the value will now be `Some(...)`, containing the return value of the closure.
 
+We can then render that result:
 
+```rust
+{{#include ../../examples/use_future.rs:render}}
+```
 
-## Restarting the Future
-
-The example we showed above will only ever run once. What happens if some value changed on the server and we need to update our future's value?
-
-Well, the UseFuture handle provides a handy "restart" method. We can wire this up to a button or some other comparison code to get a regenerating future.
 
-```rust
-fn app(cx: Scope) -> Element {
-    // set "breeds" to the current value of the future
-    let dog = use_future(&cx, (), |_| async move {
-        reqwest::get("https://dog.ceo/api/breeds/image/random")
-            .await
-            .unwrap()
-            .json::<RandomDog>()
-            .await
-    });
+## Restarting the Future
 
-    cx.render(match breeds.value() {
-        Some(Ok(val)) => rsx!(div {
-            img { src: "{val.message}"}
-            button {
-                onclick: move |_| dog.restart(),
-                "Click to fetch a new dog"
-            }
-        }),
-        Some(Err(err)) => rsx!("Failed to load dog"),
-        None => rsx!("Loading dog image!"),
-    })
-}
-```
+The `UseFuture` handle provides a `restart` method. It can be used to execute the future again, producing a new value.
 
-## With Dependencies
+## Dependencies
 
-We showed that UseFuture can be regenerated manually, but how can we automatically get it to update whenever some input value changes? This is where the "dependencies" tuple comes into play. We just need to add a value into our tuple argument and it'll be automatically cloned into our future when it starts.
+Often, you will need to run the future again every time some value (e.g. a prop) changes. Rather than `.restart`ing it manually, you can provide a tuple of "dependencies" to the hook. It will automatically re-run the future when any of those dependencies change. Example:
 
 
 ```rust
-#[inline_props]
-fn RandomDog(cx: Scope, breed: String) -> Element {
-    let dog = use_future(&cx, (breed,), |(breed)| async move {
-        reqwest::get(format!("https://dog.ceo/api/breed/{breed}/images/random"))
-            .await
-            .unwrap()
-            .json::<RandomDog>()
-            .await
-    });
-
-    // some code as before
-}
+{{#include ../../examples/use_future.rs:dependency}}
 ```

+ 33 - 0
docs/guide/src/best_practices/antipatterns.md

@@ -0,0 +1,33 @@
+# Antipatterns
+
+This example shows what not to do and provides a reason why a given pattern is considered an "AntiPattern". Most anti-patterns are considered wrong due performance reasons, or for harming code re-usability.
+
+## Unnecessarily Nested Fragments
+
+Fragments don't mount a physical element to the DOM immediately, so Dioxus must recurse into its children to find a physical DOM node. This process is called "normalization". This means that deeply nested fragments make Dioxus perform unnecessary work. Prefer one or two levels of fragments / nested components until presenting a true DOM element.
+
+Only Component and Fragment nodes are susceptible to this issue. Dioxus mitigates this with components by providing an API for registering shared state without the Context Provider pattern.
+
+```rust
+{{#include ../../examples/anti_patterns.rs:nested_fragments}}
+```
+
+## Incorrect Iterator Keys
+
+As described in the conditional rendering chapter, list items must have unique keys that are associated with the same items across renders. This helps Dioxus associate state with the contained components, and ensures good diffing performance. Do not omit keys, unless you know that the list is static and will never change.
+
+```rust
+{{#include ../../examples/anti_patterns.rs:iter_keys}}
+```
+
+## Avoid Interior Mutability in Props
+
+While it is technically acceptable to have a `Mutex` or a `RwLock` in the props, they will be difficult to use.
+
+Suppose you have a struct `User` containing the field `username: String`. If you pass a `Mutex<User>` prop to a `UserComponent` component, that component may wish to pass the username as a `&str` prop to a child component. However, it cannot pass that borrowed field down, since it only would live as long as the `Mutex`'s lock, which belongs to the `UserComponent` function. Therefore, the component will be forced to clone the `username` field.
+
+## Avoid Updating State During Render
+
+Every time you update the state, Dioxus needs to re-render the component – this is inefficient! Consider refactoring your code to avoid this.
+
+Also, if you unconditionally update the state during render, it will be re-rendered in an infinite loop.

+ 1 - 1
docs/guide/src/state/errorhandling.md → docs/guide/src/best_practices/error_handling.md

@@ -6,7 +6,7 @@ However, we haven't talked about error handling at all in this guide! In this ch
 
 
 
-## The simplest - returning None
+## The simplest  returning None
 
 Astute observers might have noticed that `Element` is actually a type alias for `Option<VNode>`. You don't need to know what a `VNode` is, but it's important to recognize that we could actually return nothing at all:
 

+ 29 - 0
docs/guide/src/best_practices/index.md

@@ -0,0 +1,29 @@
+# Best Practices
+
+## Reusable Components
+
+As much as possible, break your code down into small, reusable components and hooks, instead of implementing large chunks of the UI in a single component. This will help you keep the code maintainable – it is much easier to e.g. add, remove or re-order parts of the UI if it is organized in components.
+
+Organize your components in modules to keep the codebase easy to navigate!
+
+## Minimize State Dependencies
+
+While it is possible to share state between components, this should only be done when necessary. Any component that is associated with a particular state object needs to be re-rendered when that state changes. For this reason:
+
+- Keep state local to a component if possible
+- When sharing state through props, only pass down the specific data necessary
+
+## Reusable Libraries
+
+When publishing a library designed to work with Dioxus, we highly advise using only the core feature on the `dioxus` crate. This makes your crate compile faster, makes it more stable, and avoids bringing in incompatible libraries that might make it not compile on unsupported platforms.
+
+
+❌ Don't include unnecessary dependencies in libraries:
+```toml
+dioxus = { version = "...", features = ["web", "desktop", "full"]}
+```
+
+✅ Only add the features you need:
+```toml
+dioxus = { version = "...", features = "core"}
+```

+ 0 - 218
docs/guide/src/components/component_children.md

@@ -1,218 +0,0 @@
-# Passing children and attributes
-
-Oftentimes, you'll want to wrap some important functionality *around* your state, not directly nested *inside* another component. In these cases, you'll want to pass elements and attributes into a component and let the component place them appropriately.
-
-In this chapter, you'll learn about:
-- Passing elements into components
-- Passing attributes into components
-
-
-## The use case
-
-Let's say you're building a user interface and want to make some part of it a clickable link to another website. You would normally start with the HTML `<a>` tag, like so:
-
-```rust
-rsx!(
-    a {
-        href: "https://google.com"
-        "Link to google"
-    }
-)
-```
-
-But, what if we wanted to style our `<a>` tag? Or wrap it with some helper icon? We could abstract our RSX into its own component:
-
-
-```rust
-#[derive(Props)]
-struct ClickableProps<'a> {
-    href: &'a str,
-    title: &'a str
-}
-
-fn Clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
-    cx.render(rsx!(
-        a {
-            href: "{cx.props.href}"
-            "{cx.props.title}"
-        }
-    ))
-}
-```
-
-And then use it in our code like so:
-
-```rust
-rsx!(
-    Clickable {
-        href: "https://google.com"
-        title: "Link to Google"
-    }
-)
-```
-
-Let's say we don't just want the text to be clickable, but we want another element, like an image, to be clickable. How do we implement that?
-
-## Passing children
-
-If we want to pass an image into our component, we can just adjust our props and component to allow any `Element`.
-
-```rust
-#[derive(Props)]
-struct ClickableProps<'a> {
-    href: &'a str,
-    body: Element<'a>
-}
-
-fn Clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
-    cx.render(rsx!(
-        a {
-            href: "{cx.props.href}",
-            &cx.props.body
-        }
-    ))
-}
-```
-
-Then, at the call site, we can render some nodes and pass them in:
-
-```rust
-rsx!(
-    Clickable {
-        href: "https://google.com"
-        body: cx.render(rsx!(
-            img { src: "https://www.google.com/logos/doodles/..." }
-        ))
-    }
-)
-```
-
-## Auto Conversion of the `Children` field
-
-This pattern can become tedious in some instances, so Dioxus actually performs an implicit conversion of any `rsx` calls inside components into `Elements` at the `children` field. This means you must explicitly declare if a component can take children.
-
-```rust
-#[derive(Props)]
-struct ClickableProps<'a> {
-    href: &'a str,
-    children: Element<'a>
-}
-
-fn Clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
-    cx.render(rsx!(
-        a {
-            href: "{cx.props.href}",
-            &cx.props.children
-        }
-    ))
-}
-```
-
-Now, whenever we use `Clickable` in another component, we don't need to call `render` on child nodes - it will happen automatically!
-```rust
-rsx!(
-    Clickable {
-        href: "https://google.com"
-        img { src: "https://www.google.com/logos/doodles/...." }
-    }
-)
-```
-
-> Note: Passing children into components will break any memoization due to the associated lifetime.
-
-While technically allowed, it's an antipattern to pass children more than once in a component and will probably cause your app to crash.
-
-However, because the `Element` is transparently a `VNode`, we can actually match on it to extract the nodes themselves, in case we are expecting a specific format:
-
-```rust
-fn clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
-    match cx.props.children {
-        Some(VNode::Text(text)) => {
-            // ...
-        }
-        _ => {
-            // ...
-        }
-    }
-}
-```
-
-Passing nodes through props means that they are immutable. If you find yourself needing to mutate nodes passed through props, consider creating a new node in its place that takes on its attributes, children, and listeners.
-
-<!-- ## Passing attributes
-
-In the cases where you need to pass arbitrary element properties into a component - say to add more functionality to the `<a>` tag, Dioxus will accept any quoted fields. This is similar to adding arbitrary fields to regular elements using quotes.
-
-```rust
-
-rsx!(
-    Clickable {
-        "class": "blue-button",
-        "style": "background: red;"
-    }
-)
-
-```
-
-For a component to accept these attributes, you must add an `attributes` field to your component's properties. We can use the spread syntax to add these attributes to whatever nodes are in our component.
-
-```rust
-#[derive(Props)]
-struct ClickableProps<'a> {
-    attributes: Attributes<'a>
-}
-
-fn clickable(cx: Scope<ClickableProps<'a>>) -> Element {
-    cx.render(rsx!(
-        a {
-            ..cx.props.attributes,
-            "Any link, anywhere"
-        }
-    ))
-}
-```
-
-The quoted escapes are a great way to make your components more flexible.
- -->
-
-## Passing handlers
-
-Dioxus also provides some implicit conversions from listener attributes into an `EventHandler` for any field on components that starts with `on`. IE `onclick`, `onhover`, etc. For properties, we want to define our `on` fields as an event handler:
-
-
-```rust
-#[derive(Props)]
-struct ClickableProps<'a> {
-    onclick: EventHandler<'a, MouseEvent>
-}
-
-fn clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
-    cx.render(rsx!(
-        a {
-            onclick: move |evt| cx.props.onclick.call(evt)
-        }
-    ))
-}
-```
-
-Then, we can attach a listener at the call site:
-
-```rust
-rsx!(
-    Clickable {
-        onclick: move |_| log::info!("Clicked"),
-    }
-)
-```
-
-Currently, Dioxus does not support an arbitrary amount of listeners - they must be strongly typed in `Properties`. If you need this use case, you can pass in an element with these listeners, or dip down into the `NodeFactory` API.
-
-
-## Wrapping up
-
-In this chapter, we learned:
-- How to pass arbitrary nodes through the tree
-- How the `children` field works on component properties
-- How the `attributes` field works on component properties
-- How to convert `listeners` into `EventHandlers` for components
-- How to extend any node with custom attributes and children

BIN
docs/guide/src/components/component_example_title.png


BIN
docs/guide/src/components/component_example_votes.png


+ 0 - 292
docs/guide/src/components/exporting_components.md

@@ -1,292 +0,0 @@
-# Reusing, Importing, and Exporting Components
-
-As your application grows in size, you'll want to start breaking your UI into components and, eventually, different files. This is a great idea to encapsulate functionality of your UI and scale your team.
-
-In this chapter we'll cover:
-- Rust's modules
-- Pub/Private components
-- Structure for large components
-
-## Breaking it down
-Let's say our app looks something like this:
-
-```shell
-├── Cargo.toml
-└── src
-    └── main.rs
-```
-
-```rust
-// main.rs
-use dioxus::prelude::*;
-
-fn main() {
-    dioxus::desktop::launch(App);
-}
-
-fn App(Scope) -> Element {}
-
-#[derive(PartialEq, Props)]
-struct PostProps{}
-fn Post(Scope<PostProps>) -> Element {}
-
-#[derive(PartialEq, Props)]
-struct VoteButtonsProps {}
-fn VoteButtons(Scope<VoteButtonsProps>) -> Element {}
-
-#[derive(PartialEq, Props)]
-struct TitleCardProps {}
-fn TitleCard(Scope<TitleCardProps>) -> Element {}
-
-#[derive(PartialEq, Props)]
-struct MetaCardProps {}
-fn MetaCard(Scope<MetaCardProps>) -> Element {}
-
-#[derive(PartialEq, Props)]
-struct ActionCardProps {}
-fn ActionCard(Scope<ActionCardProps>) -> Element {}
-```
-
-That's a lot of components for one file! We've successfully refactored our app into components, but we should probably start breaking it up into a file for each component.
-
-## Breaking into different files
-
-Fortunately, Rust has a built-in module system that's much cleaner than what you might be used to in JavaScript. Because `VoteButtons`, `TitleCard`, `MetaCard`, and `ActionCard` all belong to the `Post` component, let's put them all in a folder together called "post". We'll make a file for each component and move the props and render function.
-
-```rust
-// src/post/action.rs
-
-use dioxus::prelude::*;
-
-#[derive(PartialEq, Props)]
-struct ActionCardProps {}
-fn ActionCard(Scope<ActionCardProps>) -> Element {}
-```
-
-We should also create a `mod.rs` file in the `post` folder so we can use it from our `main.rs`. Our `Post` component and its props will go into this file.
-
-```rust
-// src/post/mod.rs
-
-use dioxus::prelude::*;
-
-#[derive(PartialEq, Props)]
-struct PostProps {}
-fn Post(Scope<PostProps>) -> Element {}
-```
-
-```shell
-├── Cargo.toml
-└── src
-    ├── main.rs
-    └── post
-        ├── vote.rs
-        ├── title.rs
-        ├── meta.rs
-        ├── action.rs
-        └── mod.rs
-```
-
-In our `main.rs`, we'll want to declare the `post` module so we can access our `Post` component.
-
-```rust
-// main.rs
-use dioxus::prelude::*;
-
-fn main() {
-    dioxus::desktop::launch(App);
-}
-
-mod post;
-
-fn App(Scope) -> Element {
-    cx.render(rsx!{
-        post::Post {
-            id: Uuid::new_v4(),
-            score: 10,
-            comment_count: 10,
-            post_time: std::Instant::now(),
-            url: "example".to_string(),
-            title: "Title".to_string(),
-            original_poster: "me".to_string()
-        }
-    })
-}
-```
-
-If you tried to build this app right now, you'll get an error message saying that `Post is private, try changing it to public`. This is because we haven't properly exported our component! To fix this, we need to make sure both the Props and Component are declared as "public":
-
-```rust
-// src/post/mod.rs
-
-use dioxus::prelude::*;
-
-#[derive(PartialEq, Props)]
-pub struct PostProps {}
-pub fn Post(Scope<PostProps>) -> Element {}
-```
-
-While we're here, we also need to make sure each of our subcomponents are included as modules and exported.
-
-Our "post/mod.rs" file will eventually look like this:
-
-```rust
-use dioxus::prelude::*;
-
-mod vote;
-mod title;
-mod meta;
-mod action;
-
-#[derive(Props, PartialEq)]
-pub struct PostProps {
-    id: uuid::Uuid,
-    score: i32,
-    comment_count: u32,
-    post_time: std::time::Instant,
-    url: String,
-    title: String,
-    original_poster: String
-}
-
-pub fn Post(Scope<PostProps>) -> Element {
-    cx.render(rsx!{
-        div { class: "post-container"
-            vote::VoteButtons {
-                score: props.score,
-            }
-            title::TitleCard {
-                title: props.title,
-                url: props.url,
-            }
-            meta::MetaCard {
-                original_poster: props.original_poster,
-                post_time: props.post_time,
-            }
-            action::ActionCard {
-                post_id: props.id
-            }
-        }
-    })
-}
-```
-
-Ultimately, including and exporting components is governed by Rust's module system. [The Rust book is a great resource to learn about these concepts in greater detail.](https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html)
-
-## Final structure:
-
-```shell
-├── Cargo.toml
-└── src
-    ├── main.rs
-    └── post
-        ├── vote.rs
-        ├── title.rs
-        ├── meta.rs
-        ├── action.rs
-        └── mod.rs
-```
-
-```rust
-// main.rs:
-use dioxus::prelude::*;
-
-fn main() {
-    dioxus::desktop::launch(App);
-}
-
-mod post;
-
-fn App(Scope) -> Element {
-    cx.render(rsx!{
-        post::Post {
-            id: Uuid::new_v4(),
-            score: 10,
-            comment_count: 10,
-            post_time: std::Instant::now(),
-            url: "example".to_string(),
-            title: "Title".to_string(),
-            original_poster: "me".to_string()
-        }
-    })
-}
-```
-
-
-```rust
-// src/post/mod.rs
-use dioxus::prelude::*;
-
-mod vote;
-mod title;
-mod meta;
-mod action;
-
-#[derive(Props, PartialEq)]
-pub struct PostProps {
-    id: uuid::Uuid,
-    score: i32,
-    comment_count: u32,
-    post_time: std::time::Instant,
-    url: String,
-    title: String,
-    original_poster: String
-}
-
-pub fn Post(Scope<PostProps>) -> Element {
-    cx.render(rsx!{
-        div { class: "post-container"
-            vote::VoteButtons {
-                score: props.score,
-            }
-            title::TitleCard {
-                title: props.title,
-                url: props.url,
-            }
-            meta::MetaCard {
-                original_poster: props.original_poster,
-                post_time: props.post_time,
-            }
-            action::ActionCard {
-                post_id: props.id
-            }
-        }
-    })
-}
-```
-
-```rust
-// src/post/vote.rs
-use dioxus::prelude::*;
-
-#[derive(PartialEq, Props)]
-pub struct VoteButtonsProps {}
-pub fn VoteButtons(Scope<VoteButtonsProps>) -> Element {}
-```
-
-```rust
-// src/post/title.rs
-use dioxus::prelude::*;
-
-#[derive(PartialEq, Props)]
-pub struct TitleCardProps {}
-pub fn TitleCard(Scope<TitleCardProps>) -> Element {}
-```
-
-```rust
-// src/post/meta.rs
-use dioxus::prelude::*;
-
-#[derive(PartialEq, Props)]
-pub struct MetaCardProps {}
-pub fn MetaCard(Scope<MetaCardProps>) -> Element {}
-```
-
-```rust
-// src/post/action.rs
-use dioxus::prelude::*;
-
-#[derive(PartialEq, Props)]
-pub struct ActionCardProps {}
-pub fn ActionCard(Scope<ActionCardProps>) -> Element {}
-```

+ 0 - 42
docs/guide/src/components/index.md

@@ -1,42 +0,0 @@
-# Introduction to Components
-
-In the previous chapter, we learned about Elements and how they can be composed to create a basic user interface. Now, we'll learn how to group Elements together to form Components. We'll cover:
-
-- What makes a Component
-- How to model a component and its properties in Dioxus
-- How to "think declaratively"
-
-## What is a component?
-
-In short, a component is a special function that takes input properties and outputs an Element. Much like a function encapsulates some specific computation task, a Component encapsulates some specific rendering task – typically, rendering an isolated part of the user interface.
-
-### Real-world example
-
-Let's use a Reddit post as an example:
-
-![Reddit Post](../images/reddit_post.png)
-
-If we look at the layout of the component, we notice quite a few buttons and pieces of functionality:
-
-- Upvote/Downvote
-- View comments
-- Share
-- Save
-- Hide
-- Give award
-- Report
-- Crosspost
-- Filter by site
-- View article
-- Visit user
-
-If we included all this functionality in one `rsx!` call it would be huge! Instead, let's break the post down into Components:
-
-![Post as Component](../images/reddit_post_components.png)
-
-- **VoteButton**: Upvote/Downvote
-- **TitleCard**: Title, Filter-By-Url
-- **MetaCard**: Original Poster, Time Submitted
-- **ActionCard**: View comments, Share, Save, Hide, Give award, Report, Crosspost
-
-In this chapter, we'll learn how to define these components.

+ 0 - 232
docs/guide/src/components/propsmacro.md

@@ -1,232 +0,0 @@
-# Component Properties
-
-Dioxus components are functions that accept Props as input and output an Element. In fact, the `App` function you saw in the previous chapter was a component with no Props! Most components, however, will need to take some Props to render something useful – so, in this section, we'll learn about props:
-
-- Deriving the Props trait
-- Memoization through PartialEq
-- Optional fields on props
-- The inline_props macro
-
-## Props
-
-The input of your Component must be passed in a single struct, which must implement the `Props` trait. We can derive this trait automatically with `#[derive(Props)]`.
-
-> Dioxus `Props` is very similar to [@idanarye](https://github.com/idanarye)'s [TypedBuilder crate](https://github.com/idanarye/rust-typed-builder) and supports many of the same parameters.
-
-There are 2 flavors of Props: owned and borrowed.
-
-- All Owned Props must implement `PartialEq`
-- Borrowed props [borrow](https://doc.rust-lang.org/beta/rust-by-example/scope/borrow.html) values from the parent Component
-
-### Owned Props
-
-Owned Props are very simple – they don't borrow anything. Example:
-```rust
-// Remember: owned props must implement PartialEq!
-#[derive(PartialEq, Props)]
-struct VoteButtonProps {
-    score: i32
-}
-
-fn VoteButton(cx: Scope<VoteButtonProps>) -> Element {
-    cx.render(rsx!{
-        div {
-            div { "+" }
-            div { "{cx.props.score}"}
-            div { "-" }
-        }
-    })
-}
-```
-
-Now, we can use the VoteButton Component like we would use a regular HTML element:
-
-```rust
-fn main() {
-    dioxus::desktop::launch(App);
-}
-
-fn App(cx: Scope) -> Element {
-    cx.render(rsx! (
-        VoteButton { score: 42 }
-    ))
-}
-```
-
-And we can see that the Component indeed gets rendered:
-
-![Screenshot of running app. Text: "+ \ 42 \ -"](component_example_votes.png)
-
-> The simplest Owned Props you can have is `()` - or no value at all. This is what the `App` Component takes as props. `Scope` accepts a generic for the Props which defaults to `()`.
->
-> ```rust
->// this scope
->Scope<()>
->
->// is the same as this scope
->Scope
->```
-
-### Borrowed Props
-
-Owning props works well if your props are easy to copy around - like a single number. But what if we need to pass a larger data type, like a String from an `App` Component to a `TitleCard` subcomponent? A naive solution might be to [`.clone()`](https://doc.rust-lang.org/std/clone/trait.Clone.html) the String, creating a copy of it for the subcomponent – but this would be inefficient, especially for larger Strings.
-
-Rust allows for something more efficient – borrowing the String as a `&str`. Instead of creating a copy, this will give us a reference to the original String – this is what Borrowed Props are for!
-
-However, if we create a reference a String, Rust will require us to show that the String will not go away while we're using the reference. Otherwise, if we referenced something that doesn't exist, Bad Things could happen. To prevent this, Rust asks us to define a lifetime for the reference:
-
-```rust
-#[derive(Props)]
-struct TitleCardProps<'a> {
-    title: &'a str,
-}
-
-fn TitleCard<'a>(cx: Scope<'a, TitleCardProps<'a>>) -> Element {
-    cx.render(rsx!{
-        h1 { "{cx.props.title}" }
-    })
-}
-```
-
-This lifetime `'a` tells the compiler that as long as `title` exists, the String it was created from must also exist. Dioxus will happily accept such a component – we can now render it alongside our VoteButton!
-
-```rust
-fn App(cx: Scope) -> Element {
-    // For the sake of an example, we create the &str here.
-    // But you might as well borrow it from an owned String type.
-    let hello = "Hello Dioxus!";
-
-    cx.render(rsx! (
-        VoteButton { score: 42 },
-        TitleCard { title: hello }
-    ))
-}
-```
-![New screenshot of running app, now including a "Hello Dioxus!" heading.](component_example_title.png)
-
-## Memoization
-
-Dioxus uses Memoization for a more efficient user interface. Memoization is the process in which we check if a component actually needs to be re-rendered when its props change. If a component's properties change but they wouldn't affect the output, then we don't need to re-render the component, saving time!
-
-For example, let's say we have a component that has two children:
-
-```rust
-fn Demo(cx: Scope) -> Element {
-    // don't worry about these 2, we'll cover them later
-    let name = use_state(&cx, || String::from("bob"));
-    let age = use_state(&cx, || 21);
-
-    cx.render(rsx!{
-        Name { name: name }
-        Age { age: age }
-    })
-}
-```
-
-If `name` changes but `age` does not, then there is no reason to re-render our `Age` component since the contents of its props did not meaningfully change.
-
-Dioxus memoizes owned components. It uses `PartialEq` to determine if a component needs rerendering, or if it has stayed the same. This is why you must derive PartialEq!
-
-> This means you can always rely on props with `PartialEq` or no props at all to act as barriers in your app. This can be extremely useful when building larger apps where properties frequently change. By moving our state into a global state management solution, we can achieve precise, surgical re-renders, improving the performance of our app.
-
-Borrowed Props cannot be safely memoized. However, this is not a problem – Dioxus relies on the memoization of their parents to determine if they need to be rerendered.
-
-## Optional Props
-
-You can easily create optional fields by using the `Option<…>` type for a field:
-
-```rust
-#[derive(Props, PartialEq)]
-struct MyProps {
-    name: String,
-
-    description: Option<String>
-}
-
-fn Demo(cx: MyProps) -> Element {
-    let text = match cx.props.description {
-        Some(d) => d,             // if a value is provided
-        None => "No description"  // if the prop is omitted
-    };
-
-    cx.render(rsx! {
-        "{name}": "{text}"
-    })
-}
-```
-In this example `name` is a required prop and `description` is optional.
-This means we can completely omit the description field when calling the component:
-
-```rust
-rsx!{
-    Demo {
-        name: "Thing".to_string(),
-        // description is omitted
-    }
-}
-```
-Additionally if we provide a value we don't have to wrap it with `Some(…)`. This is done automatically for us:
-
-```rust
-rsx!{
-    Demo {
-        name: "Thing".to_string(),
-        description: "This is explains it".to_string(),
-    }
-}
-```
-
-If you want to make a prop required even though it is of type `Option` you can provide the `!optional` modifier:
-
-```rust
-#[derive(Props, PartialEq)]
-struct MyProps {
-    name: String,
-
-    #[props(!optional)]
-    description: Option<String>
-}
-```
-
-This can be especially useful if you have a type alias named `Option` in the current scope.
-
-For more information on how tags work, check out the [TypedBuilder](https://github.com/idanarye/rust-typed-builder) crate. However, all attributes for props in Dioxus are flattened (no need for `setter` syntax) and the `optional` field is new. The `optional` modifier is a combination of two separate modifiers: `default` and `strip_option` and it is automatically detected on `Option<…>` types.
-
-The full list of Dioxus' modifiers includes:
-
-- `default` - automatically add the field using its `Default` implementation
-- `optional` - alias for `default` and `strip_option`
-- `into` - automatically call `into` on the value at the callsite
-
-
-## The `inline_props` macro
-
-So far, every Component function we've seen had a corresponding ComponentProps struct to pass in props. This was quite verbose... Wouldn't it be nice to have props as simple function arguments? Then we wouldn't need to define a Props struct, and instead of typing `cx.props.whatever`, we could just use `whatever` directly!
-
-`inline_props` allows you to do just that. Instead of typing the "full" version:
-
-```rust
-#[derive(Props, PartialEq)]
-struct TitleCardProps {
-    title: String,
-}
-
-fn TitleCard(cx: Scope<TitleCardProps>) -> Element {
-    cx.render(rsx!{
-        h1 { "{cx.props.title}" }
-    })
-}
-```
-
-...you can define a function that accepts props as arguments. Then, just annotate it with `#[inline_props]`, and the macro will turn it into a regular Component for you:
-
-```rust
-#[inline_props]
-fn TitleCard(cx: Scope, title: String) -> Element {
-    cx.render(rsx!{
-        h1 { "{title}" }
-    })
-}
-```
-
-> While the new Component is shorter and easier to read, this macro should not be used by library authors since you have less control over Prop documentation.

+ 20 - 0
docs/guide/src/contributing.md

@@ -0,0 +1,20 @@
+# Contributing
+
+Development happens in the [Dioxus GitHub repository](https://github.com/DioxusLabs/dioxus). If you've found a bug or have an idea for a feature, please submit an issue (check if someone hasn't [done it already](https://github.com/DioxusLabs/dioxus/issues) though).
+
+[GitHub discussions](https://github.com/DioxusLabs/dioxus/discussions) can be used as a place to ask for help or talk about features. You can also join [our Discord channel](https://discord.gg/XgGxMSkvUM) where some development discussion happens.
+
+## Improving Docs
+
+If you'd like to improve the docs, PRs are welcome! Both Rust docs ([source](https://github.com/DioxusLabs/dioxus/tree/master/packages)) and this guide ([source](https://github.com/DioxusLabs/dioxus/tree/master/docs/guide)) can be found in the GitHub repo.
+
+## Working on the Ecosystem
+
+Part of what makes React great is the rich ecosystem. We'd like the same for Dioxus! So if you have a library in mind that you'd like to write, and that you think many people would benefit from, it will be appreciated. You can [browse npm.js](https://www.npmjs.com/search?q=keywords:react-component) for inspiration.
+
+## Bugs & Features
+
+If you've fixed [an issue that's open](https://github.com/DioxusLabs/dioxus/issues), feel free to submit a PR! You can also take a look at [the roadmap](./roadmap.md) and work on something in there. Consider [reaching out](https://discord.gg/XgGxMSkvUM) to the team first to make sure everyone's on the same page, and you don't do useless work!
+
+All pull requests (including those made by a team member) must be approved by at least one other team member.
+Larger, more nuanced decisions about design, architecture, breaking changes, trade-offs, etc. are made by team consensus.

+ 2 - 2
docs/reference/src/guide/custom_renderer.md → docs/guide/src/custom_renderer/index.md

@@ -47,7 +47,7 @@ The Dioxus diffing mechanism operates as a [stack machine](https://en.wikipedia.
 
 ### An example
 
-For the sake of understanding, lets consider this example - a very simple UI declaration:
+For the sake of understanding, lets consider this example  a very simple UI declaration:
 
 ```rust
 rsx!( h1 {"hello world"} )
@@ -219,7 +219,7 @@ fn virtual_event_from_websys_event(event: &web_sys::Event) -> VirtualEvent {
 
 ## Custom raw elements
 
-If you need to go as far as relying on custom elements for your renderer - you totally can. This still enables you to use Dioxus' reactive nature, component system, shared state, and other features, but will ultimately generate different nodes. All attributes and listeners for the HTML and SVG namespace are shuttled through helper structs that essentially compile away (pose no runtime overhead). You can drop in your own elements any time you want, with little hassle. However, you must be absolutely sure your renderer can handle the new type, or it will crash and burn.
+If you need to go as far as relying on custom elements for your renderer  you totally can. This still enables you to use Dioxus' reactive nature, component system, shared state, and other features, but will ultimately generate different nodes. All attributes and listeners for the HTML and SVG namespace are shuttled through helper structs that essentially compile away (pose no runtime overhead). You can drop in your own elements any time you want, with little hassle. However, you must be absolutely sure your renderer can handle the new type, or it will crash and burn.
 
 These custom elements are defined as unit structs with trait implementations.
 

+ 31 - 0
docs/guide/src/describing_ui/component_children.md

@@ -0,0 +1,31 @@
+# Component Children
+
+In some cases, you may wish to create a component that acts as a container for some other content, without the component needing to know what that content is. To achieve this, create a prop of type `Element`:
+
+```rust
+{{#include ../../examples/component_element_props.rs:Clickable}}
+```
+
+Then, when rendering the component, you can pass in the output of `cx.render(rsx!(...))`:
+
+```rust
+{{#include ../../examples/component_element_props.rs:Clickable_usage}}
+```
+
+> Note: Since `Element<'a>` is a borrowed prop, there will be no memoization.
+
+> Warning: While it may compile, do not include the same `Element` more than once in the RSX. The resulting behavior is unspecified.
+
+## The `children` field
+
+Rather than passing the RSX through a regular prop, you may wish to accept children similarly to how elements can have children. The "magic" `children` prop lets you achieve this:
+
+```rust
+{{#include ../../examples/component_children.rs:Clickable}}
+```
+
+This makes using the component much simpler: simply put the RSX inside the `{}` brackets – and there is no need for a `render` call or another macro!
+
+```rust
+{{#include ../../examples/component_children.rs:Clickable_usage}}
+```

+ 141 - 0
docs/guide/src/describing_ui/component_props.md

@@ -0,0 +1,141 @@
+# Component Props
+
+Just like you can pass arguments to a function, you can pass props to a component that customize its behavior! The components we've seen so far didn't accept any props – so let's write some components that do.
+
+## `#[derive(Props)]`
+
+Component props are a single struct annotated with `#[derive(Props)]`. For a component to accept props, the type of its argument must be `Scope<YourPropsStruct>`. Then, you can access the value of the props using `cx.props`.
+
+There are 2 flavors of Props structs:
+- Owned props:
+  - Don't have an associated lifetime
+  - Implement `PartialEq`, allowing for memoization (if the props don't change, Dioxus won't re-render the component)
+- Borrowed props:
+  - [Borrow](https://doc.rust-lang.org/beta/rust-by-example/scope/borrow.html) from a parent component
+  - Cannot be memoized due to lifetime constraints
+
+
+### Owned Props
+
+Owned Props are very simple – they don't borrow anything. Example:
+
+```rust
+{{#include ../../examples/component_owned_props.rs:Likes}}
+```
+
+You can then pass prop values to the component the same way you would pass attributes to an element:
+```rust
+{{#include ../../examples/component_owned_props.rs:App}}
+```
+
+![Screenshot: Likes component](./images/component_owned_props_screenshot.png)
+
+### Borrowed Props
+
+Owning props works well if your props are easy to copy around – like a single number. But what if we need to pass a larger data type, like a String from an `App` Component to a `TitleCard` subcomponent? A naive solution might be to [`.clone()`](https://doc.rust-lang.org/std/clone/trait.Clone.html) the String, creating a copy of it for the subcomponent – but this would be inefficient, especially for larger Strings.
+
+Rust allows for something more efficient – borrowing the String as a `&str` – this is what Borrowed Props are for!
+
+```rust
+{{#include ../../examples/component_borrowed_props.rs:TitleCard}}
+```
+
+We can then use the component like this:
+
+```rust
+{{#include ../../examples/component_borrowed_props.rs:App}}
+```
+![Screenshot: TitleCard component](./images/component_borrowed_props_screenshot.png)
+
+
+## Prop Options
+
+The `#[derive(Props)]` macro has some features that let you customize the behavior of props.
+
+### Optional Props
+
+You can create optional fields by using the `Option<…>` type for a field:
+
+```rust
+{{#include ../../examples/component_props_options.rs:OptionalProps}}
+```
+
+Then, you can choose to either provide them or not:
+
+```rust
+{{#include ../../examples/component_props_options.rs:OptionalProps_usage}}
+```
+
+### Explicitly Required `Option`s
+
+If you want to explicitly require an `Option`, and not an optional prop, you can annotate it with `#[props(!optional)]`:
+
+```rust
+{{#include ../../examples/component_props_options.rs:ExplicitOption}}
+```
+
+Then, you have to explicitly pass either `Some("str")` or `None`:
+
+```rust
+{{#include ../../examples/component_props_options.rs:ExplicitOption_usage}}
+```
+
+### Default Props
+
+You can use `#[props(default = 42)]` to make a field optional and specify its default value:
+
+```rust
+{{#include ../../examples/component_props_options.rs:DefaultComponent}}
+```
+
+Then, similarly to optional props, you don't have to provide it:
+
+```rust
+{{#include ../../examples/component_props_options.rs:DefaultComponent_usage}}
+```
+
+### Automatic Conversion with `.into`
+
+It is common for Rust functions to accept `impl Into<SomeType>` rather than just `SomeType` to support a wider range of parameters. If you want similar functionality with props, you can use `#[props(into)]`. For example, you could add it on a `String` prop – and `&str` will also be automatically accepted, as it can be converted into `String`:
+
+```rust
+{{#include ../../examples/component_props_options.rs:IntoComponent}}
+```
+
+Then, you can use it so:
+
+```rust
+{{#include ../../examples/component_props_options.rs:IntoComponent_usage}}
+```
+
+## The `inline_props` macro
+
+So far, every Component function we've seen had a corresponding ComponentProps struct to pass in props. This was quite verbose... Wouldn't it be nice to have props as simple function arguments? Then we wouldn't need to define a Props struct, and instead of typing `cx.props.whatever`, we could just use `whatever` directly!
+
+`inline_props` allows you to do just that. Instead of typing the "full" version:
+
+```rust
+#[derive(Props, PartialEq)]
+struct TitleCardProps {
+    title: String,
+}
+
+fn TitleCard(cx: Scope<TitleCardProps>) -> Element {
+    cx.render(rsx!{
+        h1 { "{cx.props.title}" }
+    })
+}
+```
+
+...you can define a function that accepts props as arguments. Then, just annotate it with `#[inline_props]`, and the macro will turn it into a regular Component for you:
+
+```rust
+#[inline_props]
+fn TitleCard(cx: Scope, title: String) -> Element {
+    cx.render(rsx!{
+        h1 { "{title}" }
+    })
+}
+```
+
+> While the new Component is shorter and easier to read, this macro should not be used by library authors since you have less control over Prop documentation.

+ 27 - 0
docs/guide/src/describing_ui/components.md

@@ -0,0 +1,27 @@
+# Components
+
+Just like you wouldn't want to write a complex program in a single, long, `main` function, you shouldn't build a complex UI in a single `App` function. Instead, it would be better to break down the functionality of an app in logical parts called components.
+
+A component is a Rust function, named in UpperCammelCase, that takes a `Scope` parameter and returns an `Element` describing the UI it wants to render. In fact, our `App` function is a component!
+
+```rust
+{{#include ../../examples/hello_world_desktop.rs:component}}
+```
+
+> You'll probably want to add `#![allow(non_snake_case)]` to the top of your crate to avoid warnings about the function name
+
+A Component is responsible for some rendering task – typically, rendering an isolated part of the user interface. For example, you could have an `About` component that renders a short description of Dioxus Labs:
+
+```rust
+{{#include ../../examples/components.rs:About}}
+```
+
+Then, you can render your component in another component, similarly to how elements are rendered:
+
+```rust
+{{#include ../../examples/components.rs:App}}
+```
+
+![Screenshot containing the About component twice](./images/screenshot_about_component.png)
+
+> At this point, it might seem like components are nothing more than functions. However, as you learn more about the features of Dioxus, you'll see that they are actually more powerful!

BIN
docs/guide/src/describing_ui/images/component_borrowed_props_screenshot.png


BIN
docs/guide/src/describing_ui/images/component_owned_props_screenshot.png


BIN
docs/guide/src/describing_ui/images/screenshot_about_component.png


+ 106 - 0
docs/guide/src/describing_ui/index.md

@@ -0,0 +1,106 @@
+# Describing the UI
+
+Dioxus is a *declarative* framework. This means that instead of telling Dioxus what to do (e.g. to "create an element" or "set color to red") we simply *declare* what we want the UI to look like using RSX.
+
+You have already seen a simple example or RSX syntax in the "hello world" application:
+
+```rust
+{{#include ../../examples/hello_world_desktop.rs:component}}
+```
+
+Here, we use the `rsx!` macro to *declare* that we want a `div` element, containing the text `"Hello, world!"`. Dioxus takes the RSX and constructs a UI from it.
+
+## RSX Features
+
+RSX is very similar to HTML in that it describes elements with attributes and children. Here's an empty `div` element in RSX, as well as the resulting HTML:
+
+```rust
+{{#include ../../examples/rsx_overview.rs:empty}}
+```
+```html
+<div></div>
+```
+
+### Children
+
+To add children to an element, put them inside the `{}` brackets. They can be either other elements, or text. For example, you could have an `ol` (ordered list) element, containing 3 `li` (list item) elements, each of which contains some text: 
+
+```rust
+{{#include ../../examples/rsx_overview.rs:children}}
+```
+```html
+<ol>
+    <li>First Item</li>
+    <li>Second Item</li>
+    <li>Third Item</li>
+</ol>
+```
+
+### Fragments
+
+You can also "group" elements by wrapping them in `Fragment {}`. This will not create any additional elements.
+
+> Note: you can also render multiple elements at the top level of `rsx!` and they will be automatically grouped – no need for an explicit `Fragment {}` there.
+
+```rust
+{{#include ../../examples/rsx_overview.rs:fragments}}
+```
+
+```html
+<p>First Item</p>
+<p>Second Item</p>
+<span>a group</span>
+<span>of three</span>
+<span>items</span>
+```
+
+### Attributes
+
+Attributes are also specified inside the `{}` brackets, using the `name: value` syntax. You can provide the value as a literal in the RSX:
+```rust
+{{#include ../../examples/rsx_overview.rs:attributes}}
+```
+```html
+<a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ" class="primary_button" autofocus="true">Log In</a>
+```
+
+> Note: All attributes defined in `dioxus-html` follow the snake_case naming convention. They transform their `snake_case` names to HTML's `camelCase` attributes.
+
+#### Custom Attributes
+
+Dioxus has a pre-configured set of attributes that you can use. RSX is validated at compile time to make sure you didn't specify an invalid attribute. If you want to override this behavior with a custom attribute name, specify the attribute in quotes:
+
+```rust
+{{#include ../../examples/rsx_overview.rs:custom_attributes}}
+```
+```html
+<b customAttribute="value">
+    Rust is cool
+</b>
+```
+
+### Interpolation
+
+Similarly to how you can [format](https://doc.rust-lang.org/rust-by-example/hello/print/fmt.html) Rust strings, you can also interpolate in RSX text. Use `{variable}` to Display the value of a variable in a string, or `{variable:?}` to use the Debug representation:
+
+```rust
+{{#include ../../examples/rsx_overview.rs:formatting}}
+```
+```html
+
+<div class="country-es">Coordinates: (42, 0)
+    <div>ES</div>
+    <div>42</div>
+</div>
+```
+
+### Expressions
+
+You can include arbitrary Rust expressions within RSX, but you must escape them in `[]` brackets:
+
+```rust
+{{#include ../../examples/rsx_overview.rs:expression}}
+```
+```html
+<span>DIOXUS</span>
+```

+ 63 - 0
docs/guide/src/describing_ui/special_attributes.md

@@ -0,0 +1,63 @@
+# Special Attributes
+
+While most attributes are simply passed on to the HTML, some have special behaviors.
+
+## The HTML Escape Hatch
+
+If you're working with pre-rendered assets, output from templates, or output from a JS library, then you might want to pass HTML directly instead of going through Dioxus. In these instances, reach for `dangerous_inner_html`.
+
+For example, shipping a markdown-to-Dioxus converter might significantly bloat your final application size. Instead, you'll want to pre-render your markdown to HTML and then include the HTML directly in your output. We use this approach for the [Dioxus homepage](https://dioxuslabs.com):
+
+
+```rust
+{{#include ../../examples/dangerous_inner_html.rs:dangerous_inner_html}}
+```
+
+> Note! This attribute is called "dangerous_inner_html" because it is **dangerous** to pass it data you don't trust. If you're not careful, you can easily expose [cross-site scripting (XSS)](https://en.wikipedia.org/wiki/Cross-site_scripting) attacks to your users.
+>
+> If you're handling untrusted input, make sure to sanitize your HTML before passing it into `dangerous_inner_html` – or just pass it to a Text Element to escape any HTML tags.
+
+
+## Boolean Attributes
+
+Most attributes, when rendered, will be rendered exactly as the input you provided. However, some attributes are considered "boolean" attributes and just their presence determines whether they affect the output. For these attributes, a provided value of `"false"` will cause them to be removed from the target element.
+
+So this RSX wouldn't actually render the `hidden` attribute:
+
+```rust
+{{#include ../../examples/boolean_attribute.rs:boolean_attribute}}
+```
+```html
+<div>hello</div>
+```
+
+Not all attributes work like this however. *Only the following attributes* have this behavior:
+
+- `allowfullscreen`
+- `allowpaymentrequest`
+- `async`
+- `autofocus`
+- `autoplay`
+- `checked`
+- `controls`
+- `default`
+- `defer`
+- `disabled`
+- `formnovalidate`
+- `hidden`
+- `ismap`
+- `itemscope`
+- `loop`
+- `multiple`
+- `muted`
+- `nomodule`
+- `novalidate`
+- `open`
+- `playsinline`
+- `readonly`
+- `required`
+- `reversed`
+- `selected`
+- `truespeed`
+
+For any other attributes, a value of `"false"` will be sent directly to the DOM.

+ 0 - 184
docs/guide/src/elements/conditional_rendering.md

@@ -1,184 +0,0 @@
-# Conditional Rendering
-
-Your components will often need to display different things depending on different conditions. With Dioxus, we can use Rust's normal control flow to conditionally hide, show, and modify the structure of our markup.
-
-In this chapter, you'll learn:
-- How to return different Elements depending on a condition
-- How to conditionally include an Element in your structure
-- Common patterns like matching and bool mapping
-
-## Conditionally returning Elements
-
-In some components, you might want to render different markup given some condition. The typical example for conditional rendering is showing a "Log In" screen for users who aren't logged into your app. To break down this condition, we can consider two states:
-
-- Logged in: show the app
-- Logged out: show the login screen
-
-Using the knowledge from the previous section on components, we'll start by making the app's props:
-
-```rust
-#[derive(Props, PartialEq)]
-struct AppProps {
-    logged_in: bool
-}
-```
-
-Now that we have a "logged_in" flag accessible in our props, we can render two different screens:
-
-```rust
-fn App(cx: Scope<AppProps>) -> Element {
-    if cx.props.logged_in {
-        cx.render(rsx!{
-            DashboardScreen {}
-        })
-    } else {
-        cx.render(rsx!{
-            LoginScreen {}
-        })
-    }
-}
-```
-
-When the user is logged in, then this component will return the DashboardScreen. If they're not logged in, the component will render the LoginScreen.
-
-## Using match statements
-
-Rust provides us algebraic datatypes: enums that can contain values. Using the `match` keyword, we can execute different branches of code given a condition.
-
-For instance, we could run a function that returns a Result:
-
-```rust
-fn App(cx: Scope)-> Element {
-    match get_name() {
-        Ok(name) => cx.render(rsx!( "Hello, {name}!" )),
-        Err(err) => cx.render(rsx!( "Sorry, I don't know your name, because an error occurred: {err}" )),
-    }
-}
-```
-
-We can even match against values:
-```rust
-fn App(cx: Scope)-> Element {
-    match get_name() {
-        "jack" => cx.render(rsx!( "Hey Jack, how's Diane?" )),
-        "diane" => cx.render(rsx!( "Hey Diane, how's Jack?" )),
-        name => cx.render(rsx!( "Hello, {name}!" )),
-    }
-}
-```
-
-Do note: the `rsx!` macro does not return an Element, but rather a wrapper struct for a `Closure` (an anonymous function). To turn our `rsx!` into an Element, we need to call `cx.render`.
-
-To make patterns like these less verbose, the `rsx!` macro accepts an optional first argument on which it will call `render`. Our previous component can be shortened with this alternative syntax:
-
-```rust
-fn App(cx: Scope)-> Element {
-    match get_name() {
-        "jack" => rsx!(cx, "Hey Jack, how's Diane?" ),
-        "diane" => rsx!(cx, "Hey Diana, how's Jack?" ),
-        name => rsx!(cx, "Hello, {name}!" ),
-    }
-}
-```
-
-Alternatively, for match statements, we can just return the builder itself and pass it into a final, single call to `cx.render`:
-
-```rust
-fn App(cx: Scope)-> Element {
-    let greeting = match get_name() {
-        "jack" => rsx!("Hey Jack, how's Diane?" ),
-        "diane" => rsx!("Hey Diana, how's Jack?" ),
-        name => rsx!("Hello, {name}!" ),
-    };
-    cx.render(greeting)
-}
-```
-
-## Nesting RSX
-
-By looking at other examples, you might have noticed that it's possible to include `rsx!` calls inside other `rsx!` calls. We can include anything in our `rsx!` that implements `IntoVnodeList`: a marker trait for iterators that produce Elements. `rsx!` itself implements this trait, so we can include it directly:
-
-```rust
-rsx!(
-    div {
-        rsx!(
-            "more rsx!"
-        )
-    }
-)
-```
-
-As you might expect, we can refactor this structure into two separate calls using variables:
-
-```rust
-let title = rsx!( "more rsx!" );
-
-rsx!(
-    div {
-        title
-    }
-)
-```
-
-In the case of a log-in screen, we might want to display the same NavBar and Footer for both logged in and logged out users. We can model this entirely by assigning a `screen` variable to a different Element depending on a condition:
-
-
-```rust
-let screen = match logged_in {
-    true => rsx!(DashboardScreen {}),
-    false => rsx!(LoginScreen {})
-};
-
-cx.render(rsx!{
-    Navbar {}
-    screen,
-    Footer {}
-})
-```
-
-## Rendering Nothing
-
-Sometimes, you don't want your component to return anything at all. Under the hood, the `Element` type is just an alias for `Option<VNode>`, so you can simply return `None`.
-
-This can be helpful in certain patterns where you need to perform some logical side-effects but don't want to render anything.
-
-```rust
-fn demo(cx: Scope) -> Element {
-    None
-}
-```
-
-## Boolean Mapping
-
-In the spirit of highly-functional apps, we suggest using the "boolean mapping" pattern when trying to conditionally hide/show an Element.
-
-By default, Rust lets you convert any `boolean` into an Option of any other type with [`then()`](https://doc.rust-lang.org/std/primitive.bool.html#method.then). We can use this in Components by mapping to some Element.
-
-```rust
-let show_title = true;
-rsx!(
-    div {
-        // Renders nothing by returning None when show_title is false
-        show_title.then(|| rsx!{
-            "This is the title"
-        })
-    }
-)
-```
-
-We can use this pattern for many things, including options:
-```rust
-let user_name = Some("bob");
-rsx!(
-    div {
-        // Renders nothing if user_name is None
-        user_name.map(|name| rsx!("Hello {name}"))
-    }
-)
-```
-
-## Moving Forward:
-
-In this chapter, we learned how to render different Elements from a Component depending on a condition. This is a very powerful building block to assemble complex user interfaces!
-
-In the next chapter, we'll cover how to renderer lists inside your `rsx!`.

+ 0 - 73
docs/guide/src/elements/index.md

@@ -1,73 +0,0 @@
-# Core Topics
-
-In this chapter, we'll cover some core topics about how Dioxus works and how to best leverage the features to build a beautiful, reactive app.
-
-At a very high level, Dioxus is simply a Rust framework for _declaring_ user interfaces and _reacting_ to changes.
-
-1) We declare what we want our user interface to look like given a state using Rust-based logic and control flow.
-2) We declare how we want our state to change when the user triggers an event.
-
-## Declarative UI
-
-Dioxus is a *declarative* framework. This means that instead of manually writing calls to "create element" and "set element background to red," we simply *declare* what we want the element to look like and let Dioxus handle the differences.
-
-Let's pretend that we have a stoplight we need to control - it has a color state with red, yellow, and green as options.
-
-
-Using an imperative approach, we would have to manually declare each element and then handlers for advancing the stoplight.
-
-```rust
-let container = Container::new();
-
-let green_light = Light::new().color("green").enabled(true);
-let yellow_light = Light::new().color("yellow").enabled(false);
-let red_light = Light::new().color("red").enabled(false);
-container.push(green_light);
-container.push(yellow_light);
-container.push(red_light);
-
-container.set_onclick(move |_| {
-    if red_light.enabled() {
-        red_light.set_enabled(false);
-        green_light.set_enabled(true);
-    } else if yellow_light.enabled() {
-        yellow_light.set_enabled(false);
-        red_light.set_enabled(true);
-    } else if green_light.enabled() {
-        green_light.set_enabled(false);
-        yellow_light.set_enabled(true);
-    }
-});
-```
-
-As the UI grows in scale, our logic to keep each element in the proper state would grow exponentially. This can become very unwieldy and lead to out-of-sync UIs that harm user experience.
-
-Instead, with Dioxus, we *declare* what we want our UI to look like:
-
-```rust
-let mut state = use_state(&cx, || "red");
-
-cx.render(rsx!(
-    Container {
-        Light { color: "red", enabled: state == "red", }
-        Light { color: "yellow", enabled: state == "yellow", }
-        Light { color: "green", enabled: state == "green", }
-
-        onclick: move |_| {
-            state.set(match *state {
-                "green" => "yellow",
-                "yellow" => "red",
-                "red" => "green",
-            })
-        }
-    }
-))
-```
-
-Remember: this concept is not new! Many frameworks are declarative - with React being the most popular. Declarative frameworks tend to be much more enjoyable to work with than imperative frameworks.
-
-Here's some reading about declaring UI in React:
-
-- [Difference between declarative and imperative in React.js](https://stackoverflow.com/questions/33655534/difference-between-declarative-and-imperative-in-react-js), a StackOverflow thread
-
-- [Declarative vs Imperative](https://medium.com/@myung.kim287/declarative-vs-imperative-251ce99c6c44), a blog post by Myung Kim

+ 0 - 145
docs/guide/src/elements/lists.md

@@ -1,145 +0,0 @@
-# Conditional Lists and Keys
-
-You will often want to display multiple similar components from a collection of data.
-
-In this chapter, you will learn:
-
-- How to use iterators in `rsx!`
-- How to filter and transform data into a list of Elements
-- How to create efficient lists with keys
-
-## Rendering data from lists
-
-If we wanted to build the Reddit app, then we need to implement a list of data that needs to be rendered: the list of posts. This list of posts is always changing, so we cannot just hardcode the lists into our app directly, like so:
-
-```rust
-// we shouldn't ship our app with posts that don't update!
-rsx!(
-    div {
-        Post {
-            title: "Post A",
-            votes: 120,
-        }
-        Post {
-            title: "Post B",
-            votes: 14,
-        }
-        Post {
-            title: "Post C",
-            votes: 999,
-        }
-    }
-)
-```
-
-Instead, we need to transform the list of data into a list of Elements.
-
-For convenience, `rsx!` supports any type in curly braces that implements the `IntoVnodeList` trait. Conveniently, every iterator that returns something that can be rendered as an Element also implements `IntoVnodeList`.
-
-As a simple example, let's render a list of names. First, start with our input data:
-
-```rust
-let names = ["jim", "bob", "jane", "doe"];
-```
-
-Then, we create a new iterator by calling `iter` and then [`map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map). In our `map` function, we'll render our template.
-
-```rust
-let name_list = names.iter().map(|name| rsx!(
-    li { "{name}" }
-));
-```
-
-We can include this list in the final Element:
-
-```rust
-rsx!(
-    ul {
-        name_list
-    }
-)
-```
-
-Rather than storing `name_list` in a temporary variable, we could also include the iterator inline:
-```rust
-rsx!(
-    ul {
-        names.iter().map(|name| rsx!(
-            li { "{name}" } 
-        ))
-    }
-)
-```
-
-The rendered HTML list is what you would expect:
-```html
-<ul>
-    <li> jim </li>
-    <li> bob </li>
-    <li> jane </li>
-    <li> doe </li>
-</ul>
-```
-
-## Filtering Iterators
-
-Rust's iterators are extremely powerful, especially when used for filtering tasks. When building user interfaces, you might want to display a list of items filtered by some arbitrary check.
-
-As a very simple example, let's set up a filter where we only list names that begin with the letter "j".
-
-Using the list from above, let's create a new iterator. Before we render the list with `map` as in the previous example, we'll [`filter`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter) the names to only allow those that start with "j".
-
-```rust
-let name_list = names
-    .iter()
-    .filter(|name| name.starts_with('j'))
-    .map(|name| rsx!( li { "{name}" }));
-```
-
-Rust's Iterators are very versatile – check out [their documentation](https://doc.rust-lang.org/std/iter/trait.Iterator.html) for more things you can do with them!
-
-For keen Rustaceans: notice how we don't actually call `collect` on the name list. If we `collect`ed our filtered list into new Vec, we would need to make an allocation to store these new elements, which slows down rendering. Instead, we create an entirely new _lazy_ iterator which Dioxus will consume in the `render` call. The `render` method is extraordinarily efficient, so it's best practice to let it do most of the allocations for us.
-
-## Keeping list items in order with `key`
-
-The examples above demonstrate the power of iterators in `rsx!` but all share the same issue: if your array items move (e.g. due to sorting), get inserted, or get deleted, Dioxus has no way of knowing what happened. This can cause Elements to be unnecessarily removed, changed and rebuilt when all that was needed was to change their position – this is inefficient.
-
-To solve this problem, each item in the list must be **uniquely identifiable**. You can achieve this by giving it a unique, fixed "key". In Dioxus, a key is a string that identifies an item among others in the list.
-
-```rust
-rsx!( li { key: "a" } )
-```
-
-Now, if an item has already been rendered once, Dioxus can use the key to match it up later to make the correct updates – and avoid unnecessary work.
-
-NB: the language from this section is strongly borrowed from [React's guide on keys](https://reactjs.org/docs/lists-and-keys.html).
-
-### Where to get your key
-
-Different sources of data provide different sources of keys:
-
-- _Data from a database_: If your data is coming from a database, you can use the database keys/IDs, which are unique by nature.
-- _Locally generated data_: If your data is generated and persisted locally (e.g. notes in a note-taking app), keep track of keys along with your data. You can use an incrementing counter or a package like `uuid` to generate keys for new items – but make sure they stay the same for the item's lifetime.
-
-Remember: keys let Dioxus uniquely identify an item among its siblings. A well-chosen key provides more information than the position within the array. Even if the position changes due to reordering, the key lets Dioxus identify the item throughout its lifetime.
-
-### Rules of keys
-
-- Keys must be unique among siblings. However, it’s okay to use the same keys for Elements in different arrays.
-- An item's key must not change – **don’t generate them on the fly** while rendering. Otherwise, Dioxus will be unable to keep track of which item is which, and we're back to square one.
-
-You might be tempted to use an item's index in the array as its key. In fact, that’s what Dioxus will use if you don’t specify a key at all. This is only acceptable if you can guarantee that the list is constant – i.e., no re-ordering, additions or deletions. In all other cases, do not use the index for the key – it will lead to the performance problems described above.
-
-Note that if you pass the key to a [custom component](../components/index.md) you've made, it won't receive the key as a prop. It’s only used as a hint by Dioxus itself. If your component needs an ID, you have to pass it as a separate prop:
-```rust
-Post { key: "{key}", id: "{key}" }
-```
-
-## Moving on
-
-In this section, we learned:
-- How to render lists of data
-- How to use iterator tools to filter and transform data
-- How to use keys to render lists efficiently
-
-Moving forward, we'll learn more about attributes.

+ 0 - 191
docs/guide/src/elements/special_attributes.md

@@ -1,191 +0,0 @@
-# Special Attributes
-
-Dioxus tries its hardest to stay close to React, but there are some divergences and "special behavior" that you should review before moving on.
-
-In this section, we'll cover special attributes built into Dioxus:
-
-- `dangerous_inner_html`
-- Boolean attributes
-- `prevent_default`
-- event handlers as string attributes
-- `value`, `checked`, and `selected`
-
-## The HTML escape hatch: `dangerous_inner_html`
-
-One thing you might've missed from React is the ability to render raw HTML directly to the DOM. If you're working with pre-rendered assets, output from templates, or output from a JS library, then you might want to pass HTML directly instead of going through Dioxus. In these instances, reach for `dangerous_inner_html`.
-
-For example, shipping a markdown-to-Dioxus converter might significantly bloat your final application size. Instead, you'll want to pre-render your markdown to HTML and then include the HTML directly in your output. We use this approach for the [Dioxus homepage](https://dioxuslabs.com):
-
-
-```rust
-fn BlogPost(cx: Scope) -> Element {
-    let contents = include_str!("../post.html");
-    cx.render(rsx!{
-        div {
-            class: "markdown",
-            dangerous_inner_html: "{contents}",
-        }
-    })
-}
-```
-
-> Note! This attribute is called "dangerous_inner_html" because it is **dangerous** to pass it data you don't trust. If you're not careful, you can easily expose cross-site-scripting (XSS) attacks to your users.
->
-> If you're handling untrusted input, make sure to sanitize your HTML before passing it into `dangerous_inner_html` – or just pass it to a Text Element to escape any HTML tags.
-
-
-## Boolean Attributes
-
-Most attributes, when rendered, will be rendered exactly as the input you provided. However, some attributes are considered "boolean" attributes and just their presence determines whether or not they affect the output. For these attributes, a provided value of `"false"` will cause them to be removed from the target element.
-
-So this RSX:
-
-```rust
-rsx!{
-    div {
-        hidden: "false",
-        "hello"
-    }
-}
-```
-wouldn't actually render the `hidden` attribute:
-```html
-<div>hello</div>
-```
-
-Not all attributes work like this however. *Only the following attributes* have this behavior:
-
-- `allowfullscreen`
-- `allowpaymentrequest`
-- `async`
-- `autofocus`
-- `autoplay`
-- `checked`
-- `controls`
-- `default`
-- `defer`
-- `disabled`
-- `formnovalidate`
-- `hidden`
-- `ismap`
-- `itemscope`
-- `loop`
-- `multiple`
-- `muted`
-- `nomodule`
-- `novalidate`
-- `open`
-- `playsinline`
-- `readonly`
-- `required`
-- `reversed`
-- `selected`
-- `truespeed`
-
-For any other attributes, a value of `"false"` will be sent directly to the DOM.
-
-## Stopping form input and navigation with `prevent_default`
-
-Currently, calling `prevent_default` on events in EventHandlers is not possible from Desktop/Mobile. Until this is supported, it's possible to prevent default using the `prevent_default` attribute.
-
-> Note: you cannot conditionally prevent default with this approach. This is a limitation until synchronous event handling is available across the Webview boundary
-
-To use `prevent_default`, simply attach the `prevent_default` attribute to a given element and set it to the name of the event handler you want to prevent default on. We can attach this attribute multiple times for multiple attributes.
-
-```rust
-rsx!{
-    input {
-        oninput: move |_| {},
-        prevent_default: "oninput",
-
-        onclick: move |_| {},
-        prevent_default: "onclick",
-    }
-}
-```
-<!--
-## Passing attributes into children: `..Attributes`
-
-> Note: this is an experimental, unstable feature not available in released versions of Dioxus. Feel free to skip this section.
-
-Just like Dioxus supports spreading component props into components, we also support spreading attributes into elements. This lets you pass any arbitrary attributes through components into elements.
-
-
-```rust
-#[derive(Props)]
-pub struct InputProps<'a> {
-    pub children: Element<'a>,
-    pub attributes: Attribute<'a>
-}
-
-pub fn StateInput<'a>(cx: Scope<'a, InputProps<'a>>) -> Element {
-    cx.render(rsx! (
-        input {
-            ..cx.props.attributes,
-            &cx.props.children,
-        }
-    ))
-}
-``` -->
-
-## Controlled inputs and `value`, `checked`, and `selected`
-
-In Dioxus, there is a distinction between controlled and uncontrolled inputs. Most inputs you'll use are controlled, meaning we both drive the `value` of the input and react to the `oninput`.
-
-Controlled components:
-```rust
-let value = use_state(&cx, || String::from("hello world"));
-
-rsx! {
-    input {
-        oninput: move |evt| value.set(evt.value.clone()),
-        value: "{value}",
-    }
-}
-```
-
-With uncontrolled inputs, we won't actually drive the value from the component. This has its advantages when we don't want to re-render the component when the user inputs a value. We could either select the element directly - something Dioxus doesn't support across platforms - or we could handle `oninput` and modify a value without causing an update:
-
-```rust
-let value = use_ref(&cx, || String::from("hello world"));
-
-rsx! {
-    input {
-        oninput: move |evt| *value.write_silent() = evt.value.clone(),
-        // no "value" is driven here – the input keeps track of its own value, and you can't change it
-    }
-}
-```
-
-## Strings for handlers like `onclick`
-
-For element fields that take a handler like `onclick` or `oninput`, Dioxus will let you attach a closure. Alternatively, you can also pass a string using normal attribute syntax and assign this attribute on the DOM.
-
-This lets you use JavaScript (only if your renderer can execute JavaScript).
-
-```rust
-rsx!{
-    div {
-        // handle oninput with rust
-        oninput: move |_| {},
-
-        // or handle oninput with javascript
-        oninput: "alert('hello world')",
-    }
-}
-
-```
-
-## Wrapping up
-
-In this chapter, we learned:
-- How to declare elements
-- How to conditionally render parts of your UI
-- How to render lists
-- Which attributes are "special"
-
-<!-- todo
-There's more to elements! For further reading, check out:
-
-- [Custom Elements]()
--->

+ 0 - 175
docs/guide/src/elements/vnodes.md

@@ -1,175 +0,0 @@
-# Declaring your first UI with Elements
-
-Every user interface you've ever used is just a symphony of tiny widgets working together to abstract over larger complex functions. In Dioxus, we call these tiny widgets "Elements." Using Components, you can easily compose Elements into larger groups to form even larger structures: Apps.
-
-In this chapter, we'll cover:
-- Declaring our first Element
-- Composing Elements together
-- Element properties
-
-## Declaring our first Element
-
-Because Dioxus is mostly used with HTML/CSS renderers, the default Element "collection" is HTML. Provided the `html` feature is not disabled, we can declare Elements using the `rsx!` macro:
-
-```rust
-rsx!(
-    div {}
-)
-```
-As you might expect, we can render this call using Dioxus-SSR to produce valid HTML:
-
-```rust
-dioxus::ssr::render_lazy(rsx!(
-    div {}
-))
-```
-
-Produces:
-```html
-<div></div>
-```
-
-We can construct any valid HTML tag with the `tag {}` pattern and expect the resulting HTML structure to resemble our declaration.
-
-## Composing Elements
-
-Of course, we need more complex structures to make our apps actually useful! Just like HTML, the `rsx!` macro lets us nest Elements inside of each other.
-
-```rust
-#use dioxus::prelude::*;
-rsx!(
-    div {
-        h1 {}
-        h2 {}
-        p {}
-    }
-)
-```
-As you might expect, the generated HTML for this structure would look like:
-```html
-<div>
-    <h1></h1>
-    <h2></h2>
-    <p></p>
-</div>
-```
-
-With the default configuration, any Element defined within the `dioxus-html` crate can be declared in this way. To create your own new elements, see the `Custom Elements` Advanced Guide.
-
-## Text Elements
-
-Dioxus also supports a special type of Element: Text. Text Elements do not accept children, just a string literal denoted by double quotes.
-
-```rust
-rsx! (
-    "hello world"
-)
-```
-
-Text Elements can be composed within other Elements:
-```rust
-rsx! (
-    div {
-        h1 { "hello world" }
-        p { "Some body content" }
-    }
-)
-```
-
-Text can also be formatted with any value that implements `Display`. We use the same syntax as Rust [format strings](https://www.rustnote.com/blog/format_strings.html) – which will already be familiar for Python and JavaScript users:
-
-```rust
-let name = "Bob";
-rsx! ( "hello {name}" )
-```
-
-Unfortunately, you cannot yet drop in arbitrary expressions directly into the string literal with Rust. In the cases where we need to compute a complex value, we'll want to use `format_args!` directly. Due to specifics of the `rsx!` macro (which we'll cover later), our call to `format_args` must be contained within square braces.
-
-```rust
-rsx!( [format_args!("Hello {}", if enabled { "Jack" } else { "Bob" } )] )
-```
-
-Alternatively, `&str` can be included directly, though it must also be inside square braces:
-
-```rust
-rsx!( "Hello ",  [if enabled { "Jack" } else { "Bob" }] )
-```
-
-This is different from React's way of generating arbitrary markup but fits within idiomatic Rust.
-
-Typically, with Dioxus, you'll just want to compute your substrings outside of the `rsx!` call and leverage the f-string formatting:
-
-```rust
-let name = if enabled { "Jack" } else { "Bob" };
-rsx! ( "hello {name}" )
-```
-
-## Attributes
-
-Every Element in your user interface will have some sort of properties that the renderer will use when drawing to the screen. These might inform the renderer if the component should be hidden, what its background color should be, or to give it a specific name or ID.
-
-To do this, we use the familiar struct-style syntax that Rust provides:
-
-```rust
-rsx!(
-    div {
-        hidden: "true",
-        background_color: "blue",
-        class: "card color-{mycolor}"
-    }
-)
-```
-
-Each field is defined as a method on the element in the `dioxus-html` crate. This prevents you from misspelling a field name and lets us provide inline documentation. When you need to use a field not defined as a method, you have two options:
-
-1) file an issue if the attribute _should_ be enabled
-2) add a custom attribute on-the-fly
-
-To use custom attributes, simply put the attribute name in quotes:
-
-```rust
-rsx!(
-    div {
-        "customAttr": "important data here"
-    }
-)
-```
-
-> Note: the name of the custom attribute must match exactly what you want the renderer to output. All attributes defined as methods in `dioxus-html` follow the snake_case naming convention. However, they internally translate their snake_case convention to HTML's camelCase convention. When using custom attributes, make sure the name of the attribute **exactly** matches what the renderer is expecting.
-
-All element attributes must occur *before* child elements. The `rsx!` macro will throw an error if your child elements come before any of your attributes. If you don't see the error, try editing your Rust-Analyzer IDE setting to ignore macro-errors. This is a temporary workaround because Rust-Analyzer currently throws *two* errors instead of just the one we care about.
-
-```rust
-// settings.json
-{
-  "rust-analyzer.diagnostics.disabled": [
-    "macro-error"
-  ],
-}
-```
-
-## Listeners
-
-Listeners are a special type of Attribute that only accept functions. Listeners let us attach functionality to our Elements by running a provided closure whenever the specified Listener is triggered.
-
-We'll cover listeners in more depth in the Adding Interactivity chapter, but for now, just know that every listener starts with "on" and accepts closures.
-
-```rust
-rsx!(
-    div {
-        onclick: move |_| log::debug!("div clicked!"),
-    }
-)
-```
-
-## Moving On
-
-This chapter just scratches the surface on how Elements can be defined.
-
-We learned:
-- Elements are the basic building blocks of User Interfaces
-- Elements can contain other elements
-- Elements can either be a named container or text
-- Some Elements have properties that the renderer can use to draw the UI to the screen
-
-Next, we'll compose Elements together using Rust-based logic.

+ 0 - 49
docs/guide/src/final.md

@@ -1,49 +0,0 @@
-# Congrats!
-
-Congrats! You've made it through the `learning Dioxus` book. Throughout this tutorial, you've learned a ton:
-
-- How to build User Interfaces with Elements
-- How to compose Element groups together as Components
-- How to handle user input with event listeners
-- How to manage local and global state
-- How to work with async using tasks, coroutines, and suspense
-- How to build custom hooks and handlers
-
-With any luck, you followed through the "Putting it All Together" mini guide and have your very own dog search engine app!
-
-# Next Steps and Advanced Topics
-
-Continuing on your journey with Dioxus, you can try a number of things:
-
-- Build a simple TUI app
-- Publish your search engine app
-- Deploy a WASM app to GitHub
-- Design a custom hook
-- Contribute to the ecosystem!
-
-There are a number of advanced topics we glossed over:
-
-- The underlying NodeFactory API
-- Static elements and templates
-- Anti-patterns
-- Bundling/distribution
-- Working with wasm apps
-
-# Contributing to the ecosystem
-
-Dioxus is still quite young and could use your help!
-
-The core team is actively working on:
-
-- Declarative window management (via Tauri) for Desktop apps
-- Portals for Dioxus Core
-- Mobile support
-- Integration with 3D renderers
-- Better async story (suspense, error handling)
-- Global state management
-- Web development server
-- LiveView
-- Broader platform support (iOS/Android/TV/embedded)
-
-If there's something specifically interesting to you, don't be afraid to jump in!
-

+ 45 - 0
docs/guide/src/getting_started/desktop.md

@@ -0,0 +1,45 @@
+# Desktop Application
+
+Build a standalone native desktop app that looks and feels the same across operating systems.
+
+Apps built with Dioxus are typically <5mb in size and use existing system resources, so they won't hog extreme amounts of RAM or memory.
+
+Examples:
+- [File explorer](https://github.com/DioxusLabs/example-projects/blob/master/file-explorer)
+- [WiFi scanner](https://github.com/DioxusLabs/example-projects/blob/master/wifi-scanner)
+
+[![File ExplorerExample](https://raw.githubusercontent.com/DioxusLabs/example-projects/master/file-explorer/image.png)](https://github.com/DioxusLabs/example-projects/tree/master/file-explorer)
+
+## Support
+
+The desktop is a powerful target for Dioxus, but is currently limited in capability when compared to the Web platform. Currently, desktop apps are rendered with the platform's WebView library, but your Rust code is running natively on a native thread. This means that browser APIs are *not* available, so rendering WebGL, Canvas, etc is not as easy as the Web. However, native system APIs *are* accessible, so streaming, WebSockets, filesystem, etc are all viable APIs. In the future, we plan to move to a custom webrenderer-based DOM renderer with WGPU integrations.
+
+Dioxus Desktop is built off [Tauri](https://tauri.app/). Right now there aren't any Dioxus abstractions over keyboard shortcuts, menubar, handling, etc, so you'll want to leverage Tauri – mostly [Wry](http://github.com/tauri-apps/wry/) and [Tao](http://github.com/tauri-apps/tao)) directly.
+
+## Creating a Project
+
+Create a new crate:
+
+```shell
+cargo new --bin demo
+cd demo
+```
+
+Add Dioxus with the `desktop` feature (this will edit `Cargo.toml`):
+
+```shell
+cargo add dioxus --features desktop
+```
+
+> If your system does not provide the `libappindicator3` library, like Debian/bullseye, you can enable the replacement `ayatana` with an additional flag:
+>
+>```shell
+># On Debian/bullseye use:
+>cargo add dioxus --features desktop --features ayatana
+>```
+
+Edit your `main.rs`:
+
+```rust
+{{#include ../../examples/hello_world_desktop.rs:all}}
+```

+ 2 - 1
docs/reference/src/guide/hot_reloading.md → docs/guide/src/getting_started/hot_reload.md

@@ -1,4 +1,5 @@
-# Hot Reloading
+# Setting Up Hot Reload
+
 1. Hot reloading allows much faster iteration times inside of rsx calls by interperting them and streaming the edits.
 2. It is useful when changing the styling/layout of a program, but will not help with changing the logic of a program.
 3. Currently the cli only implements hot reloading for the web renderer.

+ 74 - 0
docs/guide/src/getting_started/index.md

@@ -0,0 +1,74 @@
+# Getting Started
+
+This section will help you set up your Dioxus project!
+
+## Prerequisites
+
+### An Editor
+
+Dioxus integrates very well with the [Rust-Analyzer LSP plugin](https://rust-analyzer.github.io) which will provide appropriate syntax highlighting, code navigation, folding, and more.
+
+### Rust
+
+Head over to [https://rust-lang.org](http://rust-lang.org) and install the Rust compiler.
+
+We strongly recommend going through the [official Rust book](https://doc.rust-lang.org/book/ch01-00-getting-started.html) _completely_. However, our hope is that a Dioxus app can serve as a great first Rust project. With Dioxus, you'll learn about:
+
+- Error handling
+- Structs, Functions, Enums
+- Closures
+- Macros
+
+We've put a lot of care into making Dioxus syntax familiar and easy to understand, so you won't need deep knowledge on async, lifetimes, or smart pointers until you really start building complex Dioxus apps.
+
+### Platform-Specific Dependencies
+
+#### Windows
+
+Windows Desktop apps depend on WebView2 – a library which should be installed in all modern Windows distributions. If you have Edge installed, then Dioxus will work fine. If you *don't* have Webview2, [then you can install it through Microsoft](https://developer.microsoft.com/en-us/microsoft-edge/webview2/). MS provides 3 options:
+
+1. A tiny "evergreen" *bootstrapper* which will fetch an installer from Microsoft's CDN
+2. A tiny *installer* which will fetch Webview2 from Microsoft's CDN
+3. A statically linked version of Webview2 in your final binary for offline users
+
+For development purposes, use Option 1.
+
+#### Linux
+
+Webview Linux apps require WebkitGtk. When distributing, this can be part of your dependency tree in your `.rpm` or `.deb`. However, it's very likely that your users will already have WebkitGtk.
+
+```bash
+sudo apt install libwebkit2gtk-4.0-dev libgtk-3-dev libappindicator3-dev
+```
+
+When using Debian/bullseye `libappindicator3-dev` is no longer available but replaced by `libayatana-appindicator3-dev`.
+
+```bash
+# on Debian/bullseye use:
+sudo apt install libwebkit2gtk-4.0-dev libgtk-3-dev libayatana-appindicator3-dev
+```
+
+If you run into issues, make sure you have all the basics installed, as outlined in the [Tauri docs](https://tauri.studio/v1/guides/getting-started/prerequisites#setting-up-linux).
+
+
+#### MacOS
+
+Currently – everything for macOS is built right in! However, you might run into an issue if you're using nightly Rust due to some permissions issues in our Tao dependency (which have been resolved but not published).
+
+### Suggested Cargo Extensions
+
+If you want to keep your traditional `npm install XXX` workflow for adding packages, you might want to install `cargo-edit` and a few other fun `cargo` extensions:
+
+- [cargo-expand](https://github.com/dtolnay/cargo-expand) for expanding macro calls
+- [cargo tree](https://doc.rust-lang.org/cargo/commands/cargo-tree.html) – an integrated cargo command that lets you inspect your dependency tree
+
+
+## Setup Guides
+
+Dioxus supports multiple platforms. Depending on what you want, the setup is a bit different.
+
+- [Web](web.md): running in the browser using WASM
+- [Server Side Rendering](ssr.md): render Dioxus HTML as text
+- [Desktop](desktop.md): a standalone app using webview
+- [Mobile](mobile.md)
+- [Terminal UI](tui.md): terminal text-based graphic interface

+ 10 - 14
docs/reference/src/platforms/mobile.md → docs/guide/src/getting_started/mobile.md

@@ -1,11 +1,15 @@
-# Getting started: mobile
+# Mobile App
 
+Build a mobile app with Dioxus!
 
-Dioxus is unique in that it actually supports mobile. However, support is very young and you might need to dip down into some of the primitives until better support is ready.
+Example: [Todo App](https://github.com/DioxusLabs/example-projects/blob/master/ios_demo)
 
-Currently, only iOS is supported through us, however you *can* add android support by following the same instructions below by using the `android` guide in `cargo-mobile`.
+## Support
+Mobile is currently the least-supported renderer target for Dioxus. Mobile apps are rendered with the platform's WebView, meaning that animations, transparency, and native widgets are not currently achievable.
 
-Also, Dioxus Desktop and Dioxus Mobile share the same codebase, and dioxus-mobile currently just re-exports dioxus-desktop.
+In addition, iOS is the only supported Mobile Platform. It is possible to get Dioxus running on Android and rendered with WebView, but the Rust windowing library that Dioxus uses – tao – does not currently support Android.
+
+Mobile support is currently best suited for CRUD-style apps, ideally for internal teams who need to develop quickly but don't care much about animations or native widgets.
 
 ## Getting Set up
 
@@ -14,14 +18,13 @@ Getting set up with mobile can be quite challenging. The tooling here isn't grea
 We're going to be using `cargo-mobile` to build for mobile. First, install it:
 
 ```shell
-$ cargo install --git https://github.com/BrainiumLLC/cargo-mobile
+cargo install --git https://github.com/BrainiumLLC/cargo-mobile
 ```
 
-
 And then initialize your app for the right platform. Use the `winit` template for now. Right now, there's no "Dioxus" template in cargo-mobile.
 
 ```shell
-$ cargo mobile init 
+cargo mobile init 
 ```
 
 We're going to completely clear out the `dependencies` it generates for us, swapping out `winit` with `dioxus-mobile`.
@@ -55,7 +58,6 @@ simple_logger = "*"
 Edit your `lib.rs`:
 
 ```rust
-// main.rs
 use dioxus::prelude::*;
 
 fn main() {
@@ -70,9 +72,3 @@ fn app(cx: Scope) -> Element {
     })
 }
 ```
-
-To configure the webview, menubar, and other important desktop-specific features, checkout out some of the launch configuration in the [API reference](https://docs.rs/dioxus-mobile/).
-
-## Future Steps
-
-Make sure to read the [Dioxus Guide](https://dioxuslabs.com/guide) if you already haven't!

+ 19 - 12
docs/reference/src/platforms/ssr.md → docs/guide/src/getting_started/ssr.md

@@ -1,6 +1,17 @@
-# Getting Started: Server-Side-Rendering
+# Server-Side Rendering
+
+The Dioxus VirtualDom can be rendered server-side.
+
+[Example: Dioxus DocSite](https://github.com/dioxusLabs/docsite)
+
+## Multithreaded Support
+
+The Dioxus VirtualDom, sadly, is not currently `Send`. Internally, we use quite a bit of interior mutability which is not thread-safe. This means you can't easily use Dioxus with most web frameworks like Tide, Rocket, Axum, etc.
+
+To solve this, you'll want to spawn a VirtualDom on its own thread and communicate with it via channels.
+
+When working with web frameworks that require `Send`, it is possible to render a VirtualDom immediately to a String – but you cannot hold the VirtualDom across an await point. For retained-state SSR (essentially LiveView), you'll need to create a pool of VirtualDoms.
 
-The Dioxus VirtualDom can be rendered to a string by traversing the Element Tree. This is implemented in the `ssr` crate where your Dioxus app can be directly rendered to HTML to be served by a web server.
 
 ## Setup
 
@@ -21,21 +32,21 @@ However, for this guide, we're going to show how to use Dioxus SSR with `Axum`.
 Make sure you have Rust and Cargo installed, and then create a new project:
 
 ```shell
-$ cargo new --bin demo
-$ cd app
+cargo new --bin demo
+cd app
 ```
 
 Add Dioxus with the `ssr` feature:
 
 ```shell
-$ cargo add dioxus --features ssr
+cargo add dioxus --features ssr
 ```
 
 Next, add all the Axum dependencies. This will be different if you're using a different Web Framework
 
 ```
-$ cargo add tokio --features full
-$ cargo add axum
+cargo add tokio --features full
+cargo add axum
 ```
 
 Your dependencies should look roughly like this:
@@ -47,7 +58,7 @@ dioxus = { version = "*", features = ["ssr"] }
 tokio = { version = "1.15.0", features = ["full"] }
 ```
 
-Now, setup your Axum app to respond on an endpoint.
+Now, set up your Axum app to respond on an endpoint.
 
 ```rust
 use axum::{response::Html, routing::get, Router};
@@ -96,7 +107,3 @@ async fn app_endpoint() -> Html<String> {
 And that's it!
 
 > You might notice that you cannot hold the VirtualDom across an await point. Dioxus is currently not ThreadSafe, so it _must_ remain on the thread it started. We are working on loosening this requirement.
-
-## Future Steps
-
-Make sure to read the [Dioxus Guide](https://dioxuslabs.com/guide) if you already haven't!

+ 46 - 0
docs/guide/src/getting_started/tui.md

@@ -0,0 +1,46 @@
+# Terminal UI
+
+You can build a text-based interface that will run in the terminal using Dioxus.
+
+![Hello World screenshot](https://github.com/DioxusLabs/rink/raw/master/examples/example.png)
+
+> Note: this book was written with HTML-based platforms in mind. You might be able to follow along with TUI, but you'll have to adapt a bit.
+
+## Support
+
+TUI support is currently quite experimental. Even the project name will change. But, if you're willing to venture into the realm of the unknown, this guide will get you started.
+
+## Getting Set up
+
+
+Start by making a new package and adding our TUI feature.
+
+```shell
+cargo new --bin demo
+cd demo
+cargo add dioxus --features tui
+```
+
+Then, edit your `main.rs` with the basic template. 
+
+```rust
+{{#include ../../examples/hello_world_tui.rs}}
+```
+
+To run our app:
+
+```shell
+cargo run
+```
+
+Press "ctrl-c" to close the app. To switch from "ctrl-c" to  just "q" to quit you can launch the app with a configuration to disable the default quit and use the root TuiContext to quit on your own.
+
+```rust
+{{#include ../../examples/hello_world_tui_no_ctrl_c.rs}}
+```
+
+## Notes
+
+- Our TUI package uses flexbox for layout
+- 1px is one character lineheight. Your regular CSS px does not translate.
+- If your app panics, your terminal is wrecked. This will be fixed eventually.

+ 72 - 0
docs/guide/src/getting_started/web.md

@@ -0,0 +1,72 @@
+# Web
+
+Build single-page applications that run in the browser with Dioxus. To run on the Web, your app must be compiled to WebAssembly and depend on the `dioxus` crate with the `web` feature enabled.
+
+A build of Dioxus for the web will be roughly equivalent to the size of a React build (70kb vs 65kb), but will load significantly faster due to [WebAssembly's StreamingCompile](https://hacks.mozilla.org/2018/01/making-webassembly-even-faster-firefoxs-new-streaming-and-tiering-compiler/) option.
+
+Examples:
+- [TodoMVC](https://github.com/DioxusLabs/example-projects/tree/master/todomvc)
+- [ECommerce](https://github.com/DioxusLabs/example-projects/tree/master/ecommerce-site)
+
+[![TodoMVC example](https://github.com/DioxusLabs/example-projects/raw/master/todomvc/example.png)](https://github.com/DioxusLabs/example-projects/blob/master/todomvc)
+
+> Note: Because of the limitations of Wasm, not every crate will work with your web apps, so you'll need to make sure that your crates work without native system calls (timers, IO, etc).
+
+## Support
+
+The Web is the best-supported target platform for Dioxus.
+
+## Tooling
+
+To develop your Dioxus app for the web, you'll need a tool to build and serve your assets. We recommend using [trunk](https://trunkrs.dev) which includes a build system, Wasm optimization, a dev server, and support for SASS/CSS:
+
+```shell
+cargo install trunk
+```
+
+Make sure the `wasm32-unknown-unknown` target is installed:
+```shell
+rustup target add wasm32-unknown-unknown
+```
+
+## Creating a Project
+
+Create a new crate:
+
+```shell
+cargo new --bin demo
+cd demo
+```
+
+Add Dioxus as a dependency with the `web` feature:
+
+```bash
+cargo add dioxus --features web
+```
+
+Add an `index.html` for Trunk to use. Make sure your "mount point" element has an ID of "main":
+
+```html
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  </head>
+  <body>
+    <div id="main"> </div>
+  </body>
+</html>
+```
+
+Edit your `main.rs`:
+```rust
+{{#include ../../examples/hello_world_web.rs}}
+```
+
+
+And to serve our app:
+
+```bash
+trunk serve
+```

+ 0 - 152
docs/guide/src/hello_world.md

@@ -1,152 +0,0 @@
-# "Hello, World" desktop app
-
-Let's put together a simple "hello world" desktop application to get acquainted with Dioxus.
-
-In this chapter, we'll cover:
-
-- Starting a new Dioxus project with Cargo
-- Adding Dioxus as a dependency
-- Launching our first component as the app root
-
-### A new project with Cargo
-
-First, let's start a new project. Rust has the concept of executables and libraries. Executables have a `main.rs` and libraries have `lib.rs`. A project may have both. Our `hello world` will be an executable - we expect our app to launch when we run it! Cargo provides this for us:
-
-```shell
-$ cargo new --bin hello-dioxus
-```
-
-Now, we can `cd` into our project and poke around:
-
-```shell
-$ cd hello-dioxus
-$ tree
-.
-├── Cargo.toml
-├── .git
-├── .gitignore
-└── src
-    └── main.rs
-```
-
-We are greeted with a pre-initialized git repository, our code folder (`src`) and our project file (`Cargo.toml`).
-
-Our `src` folder holds our code. Our `main.rs` file holds our `fn main` which will be executed when our app is run.
-
-```shell
-$ more src/main.rs
-```
-
-```rust
-fn main() {
-    println!("Hello, world!");
-}
-```
-
-Right now, whenever our app is launched, "Hello world" will be echoed to the terminal.
-
-```shell
-$ cargo run
-   Compiling hello-dioxus v0.1.0
-    Finished dev [unoptimized + debuginfo] target(s) in 0.41s
-     Running `target/debug/hello-dioxus`
-Hello, world!
-```
-
-Our `Cargo.toml` file holds our dependencies and project flags.
-
-```shell
-$ cat Cargo.toml
-```
-
-```toml
-[package]
-name = "hello-dioxus"
-version = "0.1.0"
-edition = "2021"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-
-```
-
-### Adding Dioxus as a dependency
-
-To use the Dioxus library, we'll want to add the most recent version of `Dioxus` to our crate. If you have `cargo edit` installed, simply call:
-
-```shell
-$ cargo add dioxus --features desktop
-```
-
-It's very important to add `dioxus` with the `desktop` feature for this example. The `dioxus` crate is a batteries-include crate that combines a bunch of utility crates together, ensuring compatibility of the most important parts of the ecosystem. Under the hood, the `dioxus` crate configures various renderers, hooks, debug tooling, and more. The `desktop` feature ensures the we only depend on the smallest set of required crates to compile and render.
-
-If you system does not provide the `libappindicator3` library, like Debian/bullseye, you can enable the replacement `ayatana` with an additional flag:
-
-```shell
-$ # On Debian/bullseye use:
-$ cargo add dioxus --features desktop --features ayatana
-```
-
-If you plan to develop extensions for the `Dioxus` ecosystem, please use the `dioxus` crate with the `core` feature to limit the amount of dependencies your project brings in.
-
-### Our first app
-
-Now, let's edit our `main.rs` file:
-
-```rust
-use dioxus::prelude::*;
-
-
-fn main() {
-    dioxus::desktop::launch(app);
-}
-
-fn app(cx: Scope) -> Element {
-    cx.render(rsx! (
-        div { "Hello, world!" }
-    ))
-}
-```
-
-At this point, you could call `cargo run` and be greeted with a simple `Hello, World!` screen:
-
-![hello world](images/helloworld.png)
-
-### Dissecting our example
-
-The `use` statement at the top of our app imports everything from the `prelude` module. `use`-ing the prelude imports the right traits, types, and macros needed for working with Dioxus.
-
-```rust
-use dioxus::prelude::*;
-```
-
-This initialization code launches a Tokio runtime on a helper thread where your code will run. Then, the WebView renderer will be launched on the main thread. Due to platform requirements, the main thread is blocked by your app's event loop.
-
-```rust
-fn main() {
-    dioxus::desktop::launch(app);
-}
-```
-
-Finally, our app. Every component in Dioxus is a function that takes in `Context` and `Props` and returns an `Element`.
-
-```rust
-fn app(cx: Scope) -> Element {
-    cx.render(rsx! {
-        div { "Hello, world!" }
-    })
-}
-```
-
-### What is this `Scope` object?
-
-Coming from React, the `Scope` object might be confusing. In React, you'll want to store data between renders with hooks. However, hooks rely on global variables which make them difficult to integrate in multi-tenant systems like server-rendering.
-
-In Dioxus, you are given an explicit `Scope` object to control how the component renders and stores data. The `Scope` object provides a handful of useful APIs for features like suspense, rendering, and more.
-
-For now, just know that `Scope` lets you store state with hooks and render elements with `cx.render`.
-
-## Moving on
-
-Congrats! You've built your first desktop application with Dioxus. Next, we're going to learn about the basics of building interactive user interfaces.

BIN
docs/guide/src/images/01-setup-helloworld.png


Некоторые файлы не были показаны из-за большого количества измененных файлов