yew/website/docs/concepts/html/elements.md
mc1098 ed2e1ea00e
Add testing for website code blocks (#2014)
* Add doc-test to test website code snippets

Heavily inspired by tokio-rs/website repo.

* Fix code snippets to pass doc tests

Some code snippets are explicitly ignored and some are not run
to avoid having to include dependencies for one liners.

* Add website code snippet tests to CI

* Fix CI

* Remove doc-test from workspace

* Exclude doc-test from workspace

* Refactor code snippets and tests

Code snippets can import types from doc_test crate i.e.:
```rust
use doc_test::agents::EventBus;
```
This allows for moving some boilerplate away from the example and still
checks that the code compiles correctly.

Also some slight changes to some of the examples and the information
about `ComponentLink` which is deprecated.

* Move doc-test to packages

* Rename doc-test crate to website-test

The new name makes it more clear the purpose of this crate.

* fix ci
2021-08-28 13:17:28 +02:00

17 KiB

title description
Elements Both HTML and SVG elements are supported

DOM nodes

There are many reasons why you might want to create or manage DOM nodes manually in Yew, such as when integrating with JS libraries that can cause conflicts with managed components.

Using web-sys, you can create DOM elements and convert them into a Node - which can then be used as a Html value using VRef:

use yew::{
    Component, Context, html, Html, utils::document, 
    web_sys::{Element, Node}
};

struct Comp;

impl Component for Comp {
    type Message = ();
    type Properties = ();

    fn create(_ctx: &Context<Self>) -> Self {
        Self
    }

    fn view(&self, _ctx: &Context<Self>) -> Html {
        // Create a div element from the document
        let div: Element = document().create_element("div").unwrap();
        // Add content, classes etc.
        div.set_inner_html("Hello, World!");
        // Convert Element into a Node
        let node: Node = div.into();
        // Return that Node as a Html value
        Html::VRef(node)
    }
}

Dynamic tag names

When building a higher-order component you might find yourself in a situation where the element's tag name isn't static. For example, you might have a Title component which can render anything from h1 to h6 depending on a level prop. Instead of having to use a big match expression, Yew allows you to set the tag name dynamically using @{name} where name can be any expression that returns a string.

use yew::html;

let level = 5;
let text = "Hello World!".to_owned();

html! {
    <@{format!("h{}", level)} class="title">{ text }</@>
};

Boolean Attributes

Some content attributes (e.g checked, hidden, required) are called boolean attributes. In Yew, boolean attributes need to be set to a bool value:

use yew::html;

html! {
    <div hidden=true>
        { "This div is hidden." }
    </div>
};

This will result in HTML that's functionally equivalent to this:

<div hidden>This div is hidden.</div>

Setting a boolean attribute to false is equivalent to not using the attribute at all; values from boolean expressions can be used:

use yew::html;

let no = 1 + 1 != 2;

html! {
    <div hidden={no}>
        { "This div is NOT hidden." }
    </div>
};

This will result in the following HTML:

<div>This div is NOT hidden.</div>

Optional attributes for HTML elements

Most HTML attributes can use optional values (Some(x) or None). This allows us to omit the attribute if the attribute is marked as optional.

use yew::html;

let maybe_id = Some("foobar");

html! {
    <div id={maybe_id}></div>
};

If the attribute is set to None, the attribute won't be set in the DOM.

Listeners

Listener attributes need to be passed a Callback which is a wrapper around a closure. How you create your callback depends on how you wish your app to react to a listener event:

use yew::{Component, Context, html, Html};

struct MyComponent;

enum Msg {
    Click,
}

impl Component for MyComponent {
    type Message = Msg;
    type Properties = ();

    fn create(_ctx: &Context<Self>) -> Self {
        Self
    }

    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
        match msg {
            Msg::Click => {
                // Handle Click
            }
        };
        true
    }

    fn view(&self, ctx: &Context<Self>) -> Html {
        // Create a callback from a component link to handle it in a component
        let click_callback = ctx.link().callback(|_| Msg::Click);
        html! {
            <button onclick={click_callback}>
                { "Click me!" }
            </button>
        }
    }
}
use yew::{html, Component, Context, Html};
use yew_agent::{Dispatcher, Dispatched};
use website_test::agents::{MyWorker, WorkerMsg};

struct MyComponent {
    worker: Dispatcher<MyWorker>,
}

impl Component for MyComponent {
    type Message = WorkerMsg;
    type Properties = ();

    fn create(_ctx: &Context<Self>) -> Self {
        MyComponent {
            worker: MyWorker::dispatcher(),
        }
    }

    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
        self.worker.send(msg);
        false
    }

    fn view(&self, ctx: &Context<Self>) -> Html {
        // Create a callback from a worker to handle it in another context
        let click_callback = ctx.link().callback(|_| WorkerMsg::Process);
        html! {
            <button onclick={click_callback}>
                { "Click me!" }
            </button>
        }
    }
}
use yew::{Callback, Context, Component, html, Html};
use weblog::console_log;

struct MyComponent;

impl Component for MyComponent {
    type Message = ();
    type Properties = ();

    fn create(_ctx: &Context<Self>) -> Self {
        MyComponent
    }

    fn view(&self, _ctx: &Context<Self>) -> Html {
        // Create an ephemeral callback
        let click_callback = Callback::from(|_| {
            console_log!("clicked!");
        });

        html! {
            <button onclick={click_callback}>
                { "Click me!" }
            </button>
        }
    }
}

Event Types

:::tip All the event types mentioned in the following table are re-exported under yew::events. Using the types from yew::events makes it easier to ensure version compatibility than if you were to manually include web-sys as a dependency in your crate because you won't end up using a version which conflicts with the version that Yew specifies. :::

Event name web_sys Event Type
onabort Event
onauxclick MouseEvent
onblur FocusEvent
oncancel Event
oncanplay Event
oncanplaythrough Event
onchange Event
onclick MouseEvent
onclose Event
oncontextmenu MouseEvent
oncuechange Event
ondblclick MouseEvent
ondrag DragEvent
ondragend DragEvent
ondragenter DragEvent
ondragexit DragEvent
ondragleave DragEvent
ondragover DragEvent
ondragstart DragEvent
ondrop DragEvent
ondurationchange Event
onemptied Event
onended Event
onerror Event
onfocus FocusEvent
onfocusin FocusEvent
onfocusout FocusEvent
onformdata Event
oninput InputEvent
oninvalid Event
onkeydown KeyboardEvent
onkeypress KeyboardEvent
onkeyup KeyboardEvent
onload Event
onloadeddata Event
onloadedmetadata Event
onloadstart ProgressEvent
onmousedown MouseEvent
onmouseenter MouseEvent
onmouseleave MouseEvent
onmousemove MouseEvent
onmouseout MouseEvent
onmouseover MouseEvent
onmouseup MouseEvent
onpause Event
onplay Event
onplaying Event
onprogress ProgressEvent
onratechange Event
onreset Event
onresize Event
onscroll Event
onsecuritypolicyviolation Event
onseeked Event
onseeking Event
onselect Event
onslotchange Event
onstalled Event
onsubmit FocusEvent
onsuspend Event
ontimeupdate Event
ontoggle Event
onvolumechange Event
onwaiting Event
onwheel WheelEvent
oncopy Event
oncut Event
onpaste Event
onanimationcancel AnimationEvent
onanimationend AnimationEvent
onanimationiteration AnimationEvent
onanimationstart AnimationEvent
ongotpointercapture PointerEvent
onloadend ProgressEvent
onlostpointercapture PointerEvent
onpointercancel PointerEvent
onpointerdown PointerEvent
onpointerenter PointerEvent
onpointerleave PointerEvent
onpointerlockchange Event
onpointerlockerror Event
onpointermove PointerEvent
onpointerout PointerEvent
onpointerover PointerEvent
onpointerup PointerEvent
onselectionchange Event
onselectstart Event
onshow Event
ontouchcancel TouchEvent
ontouchend TouchEvent
ontouchmove TouchEvent
ontouchstart TouchEvent
ontransitioncancel TransitionEvent
ontransitionend TransitionEvent
ontransitionrun TransitionEvent
ontransitionstart TransitionEvent

Relevant examples