+ }
+ }
+}
+
+// The page component can be called either with the sidebar or without:
+
+pub fn render_page(with_sidebar: bool) -> Html {
+ if with_sidebar {
+ // Page with sidebar
+ html! {
+
+ }} />
+ }
+ } else {
+ // Page without sidebar
+ html! {
+
+ }
+ }
+}
+```
+
+## Further Reading
+
+- For a real-world example of this pattern, check out the yew-router source code. For a more advanced example, check out the [nested-list example](https://github.com/yewstack/yew/tree/master/examples/nested_list) in the main yew repository.
diff --git a/website/versioned_docs/version-0.21/advanced-topics/how-it-works.mdx b/website/versioned_docs/version-0.21/advanced-topics/how-it-works.mdx
new file mode 100644
index 00000000000..2a281690057
--- /dev/null
+++ b/website/versioned_docs/version-0.21/advanced-topics/how-it-works.mdx
@@ -0,0 +1,74 @@
+---
+title: 'How it works'
+description: 'Low level details about the framework'
+---
+
+# Low-level library internals
+
+## Under the hood of the `html!` macro
+
+The `html!` macro turns code written in a custom HTML-like syntax into valid Rust code. Using this
+macro is not necessary for developing Yew applications, but it is recommended. The code generated
+by this macro makes use of the public Yew library API which can be used directly if you wish. Note
+that some methods used are undocumented intentionally to avoid accidental misuse. With each
+update of `yew-macro`, the generated code will be more efficient and handle any breaking changes
+without many (if any) modifications to the `html!` syntax.
+
+Because the `html!` macro allows you to write code in a declarative style, your UI layout code will
+closely match the HTML that is generated for the page. This becomes increasingly useful as your
+application gets more interactive and your codebase gets larger. Rather than manually writing
+all of the code to manipulate the DOM yourself, the macro will handle it for you.
+
+Using the `html!` macro can feel pretty magical, but it has nothing to hide. If you are curious about
+how it works, try expanding the `html!` macro calls in your program. There is a useful command called
+`cargo expand` which allows you to see the expansion of Rust macros. `cargo expand` does not ship with
+`cargo` by default so you will need to install it with `cargo install cargo-expand` if you have not
+already. [Rust-Analyzer](https://rust-analyzer.github.io/) also provides a mechanism for
+[obtaining macro output from within an IDE](https://rust-analyzer.github.io/manual.html#expand-macro-recursively).
+
+Output from the `html!` macro is often pretty terse! This is a feature: machine-generated code can
+sometimes clash with other code in an application. To prevent issues, `proc_macro`
+"hygiene" is adhered to. Some examples include:
+
+1. Instead of using `yew::` the macro generates `::yew::` to make sure that the
+ Yew package is referenced correctly. This is also why `::alloc::vec::Vec::new()` is called instead
+ of just `Vec::new()`.
+2. Due to potential trait method name collisions, `` is used to make sure that we are
+ using members from the correct trait.
+
+## What is a virtual DOM?
+
+The DOM ("document object model") is a representation of the HTML content that is managed by the browser
+for your web page. A "virtual" DOM is simply a copy of the DOM that is held in application memory. Managing
+a virtual DOM results in a higher memory overhead, but allows for batching and faster reads by avoiding
+or delaying the use of browser APIs.
+
+Having a copy of the DOM in memory can be helpful for libraries that promote the use of
+declarative UIs. Rather than needing specific code for describing how the DOM should be modified
+in response to a user event, the library can use a generalized approach with DOM "diffing". When a Yew
+component is updated and wants to change how it is rendered, the Yew library will build a second copy
+of the virtual DOM and directly compare it to a virtual DOM which mirrors what is currently on screen.
+The "diff" (or difference) between the two can be broken down into incremental updates and applied in
+a batch with browser APIs. Once the updates are applied, the old virtual DOM copy is discarded and the
+new copy is saved for future diff checks.
+
+This "diff" algorithm can be optimized over time to improve the performance of complex applications.
+Since Yew applications are run with WebAssembly, we believe that Yew has a competitive edge to adopt
+more sophisticated algorithms in the future.
+
+The Yew virtual DOM is not exactly one-to-one with the browser DOM. It also includes "lists" and
+"components" for organizing DOM elements. A list can simply be an ordered list of elements but can
+also be much more powerful. By annotating each list element with a "key", application developers
+can help Yew make additional optimizations to ensure that when a list changes, the least amount
+of work is done to calculate the diff update. Similarly, components provide custom logic to
+indicate whether a re-render is required to help with performance.
+
+## Yew scheduler and component-scoped event loop
+
+_Contribute to the docs â explain how `yew::scheduler` and `yew::html::scope` work in depth_
+
+## Further reading
+
+- [More information about macros from the Rust Book](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)
+- [More information about `cargo-expand`](https://github.com/dtolnay/cargo-expand)
+- [The API documentation for `yew::virtual_dom`](https://docs.rs/yew/*/yew/virtual_dom/index.html)
diff --git a/website/versioned_docs/version-0.21/advanced-topics/immutable.mdx b/website/versioned_docs/version-0.21/advanced-topics/immutable.mdx
new file mode 100644
index 00000000000..332ed94164f
--- /dev/null
+++ b/website/versioned_docs/version-0.21/advanced-topics/immutable.mdx
@@ -0,0 +1,24 @@
+---
+title: 'Immutable Types'
+description: 'Immutable data structures for Yew'
+---
+
+## What are immutable types?
+
+These are types that you can instantiate but never mutate the values. In order
+to update a value, you must instantiate a new value.
+
+## Why using immutable types?
+
+Properties, like in React, are propagated from ancestors to
+children. This means that the properties must live when each component is
+updated. This is why properties should âideallyâ be cheap to clone. To
+achieve this we usually wrap things in `Rc`.
+
+Immutable types are a great fit for holding property's values because they can
+be cheaply cloned when passed from component to component.
+
+## Further reading
+
+- [Immutable example](https://github.com/yewstack/yew/tree/master/examples/immutable)
+- [Crate `implicit-clone`](https://docs.rs/implicit-clone/)
diff --git a/website/versioned_docs/version-0.21/advanced-topics/optimizations.mdx b/website/versioned_docs/version-0.21/advanced-topics/optimizations.mdx
new file mode 100644
index 00000000000..9aef595c93b
--- /dev/null
+++ b/website/versioned_docs/version-0.21/advanced-topics/optimizations.mdx
@@ -0,0 +1,163 @@
+---
+title: 'Optimizations & Best Practices'
+sidebar_label: Optimizations
+description: 'Make your app faster'
+---
+
+## Using smart pointers effectively
+
+**Note: if you're unsure about some of the terms used in this section, the Rust Book has a useful
+[chapter about smart pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html).**
+
+To avoid cloning large amounts of data to create props when re-rendering, we can use
+smart pointers to only clone a reference to the data instead of the data itself. If you pass
+references to the relevant data in your props and child components instead of the actual data you
+can avoid cloning any data until you need to modify it in the child component, where you can
+use `Rc::make_mut` to clone and obtain a mutable reference to the data you want to alter.
+
+This brings further benefits in `Component::changed` when working out whether prop changes require
+the component to re-render. This is because instead of comparing the value of the data the
+underlying pointer addresses (i.e. the position in a machine's memory where the data is stored) can
+instead be compared; if two pointers point to the same data then the value of the data they point to
+must be the same. Note that the inverse might not be true! Even if two pointer addresses differ the
+underlying data might still be the same - in this case you should compare the underlying data.
+
+To do this comparison you'll need to use `Rc::ptr_eq` instead of just using `PartialEq` (which is
+automatically used when comparing data using the equality operator `==`). The Rust documentation
+has [more details about `Rc::ptr_eq`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq).
+
+This optimization is most useful for data types that don't implement `Copy`. If you can copy your
+data cheaply, then it isn't worth putting it behind a smart pointer. For structures that
+can be data-heavy like `Vec`s, `HashMap`s, and `String`s using smart pointers is likely to bring
+performance improvements.
+
+This optimization works best if the values are never updated by the children, and even better if
+they are rarely updated by parents. This makes `Rc<_>s` a good choice for wrapping property values
+in pure components.
+
+However, it must be noted that unless you need to clone the data yourself in the child component,
+this optimization is not only useless, but it also adds the unnecessary cost of reference counting. Props
+in Yew are already reference counted and no data clones occur internally.
+
+## View functions
+
+For code readability reasons, it often makes sense to migrate sections of `html!` to their own
+functions. Not only does this make your code more readable because it reduces the amount of
+indentation present, it also encourages good design patterns â particularly around building
+composable applications because these functions can be called in multiple places which reduces the
+amount of code that has to be written.
+
+## Pure Components
+
+Pure components are components that don't mutate their state, only displaying content and
+propagating messages up to normal, mutable components. They differ from view functions in that they
+can be used from within the `html!` macro using the component syntax \(``\)
+instead of expression syntax \(`{some_view_function()}`\), and that depending on their
+implementation, they can be memoized (this means that once a function is called its value is "saved"
+so that if it's called with the same arguments more than once it doesn't have to recompute its value
+and can just return the saved value from the first function call) - preventing re-renders for
+identical props. Yew compares the props internally and so the UI is only re-rendered if the props change.
+
+## Reducing compile time using workspaces
+
+Arguably, the largest drawback to using Yew is the long time it takes to compile Yew apps. The time
+taken to compile a project seems to be related to the quantity of code passed to the `html!` macro.
+This tends to not be much of an issue for smaller projects, but for larger applications, it makes
+sense to split code across multiple crates to minimize the amount of work the compiler has to do for
+each change made to the application.
+
+One possible approach is to make your main crate handle routing/page selection, and then make a
+different crate for each page, where each page could be a different component or just a big
+function that produces `Html`. Code that is shared between the crates containing different parts of
+the application could be stored in a separate crate which the project depends on.
+In the best-case scenario, you go from rebuilding all of your code on each compile to rebuilding
+only the main crate, and one of your page crates. In the worst case, where you edit something in the
+"common" crate, you will be right back to where you started: compiling all code that depends on that
+commonly shared crate, which is probably everything else.
+
+If your main crate is too heavyweight, or you want to rapidly iterate on a deeply nested page \(eg.
+a page that renders on top of another page\), you can use an example crate to create a simplified
+implementation of the main page and additionally render the component you are working on.
+
+## Reducing binary sizes
+
+- optimize Rust code
+- `cargo.toml` \( defining release profile \)
+- optimize wasm code using `wasm-opt`
+
+**Note: more information about reducing binary sizes can be found in the
+[Rust Wasm Book](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size).**
+
+### Cargo.toml
+
+It is possible to configure release builds to be smaller using the available settings in the
+`[profile.release]` section of your `Cargo.toml`.
+
+```toml, title=Cargo.toml
+[profile.release]
+# less code to include into binary
+panic = 'abort'
+# optimization over all codebase ( better optimization, slower build )
+codegen-units = 1
+# optimization for size ( more aggressive )
+opt-level = 'z'
+# optimization for size
+# opt-level = 's'
+# link time optimization using using whole-program analysis
+lto = true
+```
+
+### Nightly Cargo configuration
+
+You can also gain additional benefits from experimental nightly features of rust and
+cargo. To use the nightly toolchain with `trunk`, set the `RUSTUP_TOOLCHAIN="nightly"` environment
+variable. Then, you can configure unstable rustc features in your `.cargo/config.toml`.
+Refer to the doc of [unstable features], specifically the section about [`build-std`] and
+[`build-std-features`], to understand the configuration.
+
+```toml, title=".cargo/config.toml"
+[unstable]
+# Requires the rust-src component. `rustup +nightly component add rust-src`
+build-std = ["std", "panic_abort"]
+build-std-features = ["panic_immediate_abort"]
+```
+
+[unstable features]: https://doc.rust-lang.org/cargo/reference/unstable.html
+[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std
+[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features
+
+:::caution
+The nightly rust compiler can contain bugs, such as [this one](https://github.com/yewstack/yew/issues/2696),
+that require occasional attention and tweaking. Use these experimental options with care.
+:::
+
+### wasm-opt
+
+Further, it is possible to optimize the size of `wasm` code.
+
+The Rust Wasm Book has a section about reducing the size of Wasm binaries:
+[Shrinking .wasm size](https://rustwasm.github.io/book/game-of-life/code-size.html)
+
+- using `wasm-pack` which by default optimizes `wasm` code in release builds
+- using `wasm-opt` directly on `wasm` files.
+
+```text
+wasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm
+```
+
+#### Build size of 'minimal' example in yew/examples/
+
+Note: `wasm-pack` combines optimization for Rust and Wasm code. `wasm-bindgen` is used in this example without any Rust size optimization.
+
+| used tool | size |
+| :-------------------------- | :---- |
+| wasm-bindgen | 158KB |
+| wasm-bindgen + wasm-opt -Os | 116KB |
+| wasm-pack | 99 KB |
+
+## Further reading:
+
+- [The Rust Book's chapter on smart pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)
+- [Information from the Rust Wasm Book about reducing binary sizes](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)
+- [Documentation about Rust profiles](https://doc.rust-lang.org/cargo/reference/profiles.html)
+- [binaryen project](https://github.com/WebAssembly/binaryen)
diff --git a/website/versioned_docs/version-0.21/advanced-topics/portals.mdx b/website/versioned_docs/version-0.21/advanced-topics/portals.mdx
new file mode 100644
index 00000000000..9fd76fb37f0
--- /dev/null
+++ b/website/versioned_docs/version-0.21/advanced-topics/portals.mdx
@@ -0,0 +1,64 @@
+---
+title: 'Portals'
+description: 'Rendering into out-of-tree DOM nodes'
+---
+
+## What is a portal?
+
+Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.
+`yew::create_portal(child, host)` returns an `Html` value that renders `child` not hierarchically under its parent component,
+but as a child of the `host` element.
+
+## Usage
+
+Typical uses of portals can include modal dialogs and hovercards, as well as more technical applications
+such as controlling the contents of an element's
+[`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/Element/shadowRoot), appending
+stylesheets to the surrounding document's `` and collecting referenced elements inside a
+central `` element of an `