--- title: 'Tutorial' slug: /tutorial --- ## Introduction In this hands-on tutorial, we will take a look at how we can use Yew to build web applications. **Yew** is a modern [Rust](https://www.rust-lang.org/) framework for building front-end web apps using [WebAssembly](https://webassembly.org/). Yew encourages a reusable, maintainable, and well-structured architecture by leveraging Rust's powerful type system. A large ecosystem of community-created libraries, known in Rust as [crates](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html), provide components for commonly-used patterns such as state management. [Cargo](https://doc.rust-lang.org/cargo/), the package manager for Rust, allows us to take advantage of the numerous crates available on [crates.io](https://crates.io), such as Yew. ### What we are going to build Rustconf is an intergalactic gathering of the Rust community that happens annually. Rustconf 2020 had a plethora of talks that provided a good amount of information. In this hands-on tutorial, we will be building a web application to help fellow Rustaceans get an overview of the talks and watch them all from one page. ## Setting up ### Prerequisites This tutorial assumes you are already familiar with Rust. If you are new to Rust, the free [Rust Book](https://doc.rust-lang.org/book/ch00-00-introduction.html) offers a great starting point for beginners and continues to be an excellent resource even for experienced Rust developers. Ensure the latest version of Rust is installed by running `rustup update` or by [installing rust](https://www.rust-lang.org/tools/install) if you have not already done so. After installing Rust, you can use Cargo to install `trunk` by running: ```bash cargo install trunk ``` We will also need to add the WASM build target by running: ```bash rustup target add wasm32-unknown-unknown ``` ### Setting up the project First, create a new cargo project: ```bash cargo new yew-app cd yew-app ``` To verify the Rust environment is set up properly, run the initial project using the cargo build tool. After the output about the build process, you should see the expected "Hello, world!" message. ```bash cargo run ``` ## Our first static page To convert this simple command line application to a basic Yew web application, a few changes are needed. Update the files as follows: ```toml title="Cargo.toml" {7} [package] name = "yew-app" version = "0.1.0" edition = "2021" [dependencies] yew = { git = "https://github.com/yewstack/yew/", features = ["csr"] } ``` :::info You only need the feature `csr` if you are building an application. It will enable the `Renderer` and all client-side rendering-related code. If you are making a library, do not enable this feature as it will pull in client-side rendering logic into the server-side rendering bundle. If you need the Renderer for testing or examples, you should enable it in the `dev-dependencies` instead. ::: ```rust ,no_run title="src/main.rs" use yew::prelude::*; #[function_component(App)] fn app() -> Html { html! {

{ "Hello World" }

} } fn main() { yew::Renderer::::new().render(); } ``` Now, let's create an `index.html` at the root of the project. ```html title="index.html" ``` ### Start the development server Run the following command to build and serve the application locally. ```bash trunk serve --open ``` :::info Remove option '--open' to not open your default browser `trunk serve`. ::: Trunk will open your application in your default browser, watch the project directory and helpfully rebuild your application if you modify any source files. This will fail if the socket is being used by another application. By default server will listening at address '127.0.0.1' and port '8080' => [http://localhost:8080](http://127.0.0.1:8080). To change it, create the following file and edit as needed: ```toml title="Trunk.toml" [serve] # The address to serve on LAN. address = "127.0.0.1" # The address to serve on WAN. # address = "0.0.0.0" # The port to serve on. port = 8000 ``` If you are curious, you can run `trunk help` and `trunk help ` for more details on what is happening. ### Congratulations You have now successfully set up your Yew development environment and built your first Yew web application. ## Building HTML Yew makes use of Rust's procedural macros and provides us with a syntax similar to JSX (an extension to JavaScript which allows you to write HTML-like code inside JavaScript) to create the markup. ### Converting classic HTML Since we already have a pretty good idea of what our website will look like, we can simply translate our mental draft into a representation compatible with `html!`. If you are comfortable writing simple HTML, you should have no problem writing marking inside `html!`. It is important to note that the macro does differ from HTML in a few ways: 1. Expressions must be wrapped in curly braces (`{ }`) 2. There must only be one root node. If you want to have multiple elements without wrapping them in a container, an empty tag/fragment (`<> ... `) is used 3. Elements must be closed properly. We want to build a layout that looks something like this in raw HTML: ```html

RustConf Explorer

Videos to watch

John Doe: Building and breaking things

Jane Smith: The development process

Matt Miller: The Web 7.0

Tom Jerry: Mouseless development

John Doe: Building and breaking things

video thumbnail
``` Now, let's convert this HTML into `html!`. Type (or copy/paste) the following snippet into the body of `app` function such that the value of `html!` is returned by the function ```rust ,ignore html! { <>

{ "RustConf Explorer" }

{"Videos to watch"}

{ "John Doe: Building and breaking things" }

{ "Jane Smith: The development process" }

{ "Matt Miller: The Web 7.0" }

{ "Tom Jerry: Mouseless development" }

{ "John Doe: Building and breaking things" }

video thumbnail
} ``` Refresh the browser page, and you should see the following output displayed: ![Running WASM application screenshot](/img/tutorial_application_screenshot.png) ### Using Rust language constructs in the markup A big advantage of writing markup in Rust is that we get all the coolness of Rust in our markup. Now, instead of hardcoding the list of videos in the HTML, let's define them as a `Vec` of `Video` structs. We create a simple `struct` (in `main.rs` or any file of our choice) that will hold our data. ```rust struct Video { id: usize, title: String, speaker: String, url: String, } ``` Next, we will create instances of this struct in our `app` function and use those instead of hardcoding the data: ```rust use website_test::tutorial::Video; // replace with your own path let videos = vec![ Video { id: 1, title: "Building and breaking things".to_string(), speaker: "John Doe".to_string(), url: "https://youtu.be/PsaFVLr8t4E".to_string(), }, Video { id: 2, title: "The development process".to_string(), speaker: "Jane Smith".to_string(), url: "https://youtu.be/PsaFVLr8t4E".to_string(), }, Video { id: 3, title: "The Web 7.0".to_string(), speaker: "Matt Miller".to_string(), url: "https://youtu.be/PsaFVLr8t4E".to_string(), }, Video { id: 4, title: "Mouseless development".to_string(), speaker: "Tom Jerry".to_string(), url: "https://youtu.be/PsaFVLr8t4E".to_string(), }, ]; ``` To display them, we need to convert the `Vec` into `Html`. We can do that by creating an iterator, mapping it to `html!` and collecting it as `Html`: ```rust ,ignore let videos = videos.iter().map(|video| html! {

{format!("{}: {}", video.speaker, video.title)}

}).collect::(); ``` :::tip Keys on list items help Yew keep track of which items have changed in the list, resulting in faster re-renders. [It is always recommended to use keys in lists](/concepts/html/lists.mdx#keyed-lists). ::: And finally, we need to replace the hardcoded list of videos with the `Html` we created from the data: ```rust ,ignore {6-10} html! { <>

{ "RustConf Explorer" }

{ "Videos to watch" }

-

{ "John Doe: Building and breaking things" }

-

{ "Jane Smith: The development process" }

-

{ "Matt Miller: The Web 7.0" }

-

{ "Tom Jerry: Mouseless development" }

+ { videos }
// ... } ``` ## Components Components are the building blocks of Yew applications. By combining components, which can be made of other components, we build our application. By structuring our components for re-usability and keeping them generic, we will be able to use them in multiple parts of our application without having to duplicate code or logic. The `app` function we have been using so far is a component, called `App`. It is a "function component". There are two different types of components in Yew. 1. Struct Components 2. Function Components In this tutorial, we will be using function components. Now, let's split up our `App` component into smaller components. We begin by extracting the videos list into its own component. ```rust ,compile_fail use yew::prelude::*; struct Video { id: usize, title: String, speaker: String, url: String, } #[derive(Properties, PartialEq)] struct VideosListProps { videos: Vec