Html

Html elements are the building blocks of web pages. While other rust frameworks aim for a JSX-like syntax, this library uses a more traditional approach. The goal is to provide a simple and efficient way to create HTML elements without the need for complex syntax, we use the idomatic rust builder pattern.

Natrix uses a single HtmlElement struct to represent all HTML elements. But exposes helper functions for each tag. These are found along side the HtmlElement struct in the html_elements module. Which will most commonly be used via the e alias in the prelude module.

extern crate natrix;
use natrix::prelude::*;
let _: e::HtmlElement<(), _> =
e::div()
;

If you need to construct a element with a tag not found in the library you can use HtmlElement::new.

extern crate natrix;
use natrix::prelude::*;
let _: e::HtmlElement<(), ()> =
e::HtmlElement::new("custom_tag")
;

Children

Children are added using the .child method. This method takes a single child element and adds it to the parent element.

extern crate natrix;
use natrix::prelude::*;
let _: e::HtmlElement<(), _> =
e::div()
    .child(e::button())
    .child(e::h1().child("Hello World!"))
;

tip

the .text method is a alias for .child

Child elements can be any type that implements the Element trait, including other HtmlElement instances, and stdlib types like String, &str, i32, as well as containers such as Option and Result.

Child elements can also be reactive as closures implement the Element trait.

extern crate natrix;
use natrix::prelude::*;

#[derive(Component)]
struct MyComponent {
    pub is_active: bool,
}

impl Component for MyComponent {
    fn render() -> impl Element<Self> {
e::div()
    .class("my-component")
    .child(e::button()
        .text("Click me!")
        .on::<events::Click>(|ctx: E<Self>, _| {
            *ctx.is_active = !*ctx.is_active;
        })
    )
    .child(|ctx: R<Self>| {
        if *ctx.is_active {
            Some(e::p().text("Active!"))
        } else {
            None
        }
    })
    }
}

Attributes

Attributes are set using the .attr method. This method takes a key and a value, and sets the attribute on the element.

extern crate natrix;
use natrix::prelude::*;
let _: e::HtmlElement<(), _> =
e::div()
    .attr("data-foo", "bar")
    .attr("data-baz", "qux")
;

Most standard html attributes have helper functions, for example id, class, href, src, etc. For non-global attributes natrix only exposes them on the supporting elements.

extern crate natrix;
use natrix::prelude::*;
let _: e::HtmlElement<(), _> =
e::a()
    .href("https://example.com")
    .target("_blank")
    .rel("noopener noreferrer")
;

But the following wont compile:

extern crate natrix;
use natrix::prelude::*;
let _: e::HtmlElement<(), _> =
e::div()
    .target("_blank") // error: no method named `target` found for struct `HtmlElement<_, _div>`
;

Attributes can be set by anything that implements the ToAttribute trait, this includes numberics, Option, and bool, and others. Attributes can also be reactive as closures implement the ToAttribute trait.

extern crate natrix;
use natrix::prelude::*;

#[derive(Component)]
struct MyComponent {
    pub is_active: bool,
}

impl Component for MyComponent {
    fn render() -> impl Element<Self> {
e::button()
    .class("my-button")
    .disabled(|ctx: R<Self>| !*ctx.is_active)
    .text("Click me!")
    .on::<events::Click>(|ctx: E<Self>, _| {
        *ctx.is_active = !*ctx.is_active;
    })
    }
}

Classes

The .class method is not a alias for .attr, it will add the class to the element, and not replace it. This is because the class attribute is a special case in HTML, and is used to apply CSS styles to elements. The .class method will add the class to the element, and not replace any existing ones.

extern crate natrix;
use natrix::prelude::*;
let _: e::HtmlElement<(), _> =
e::div()
    .class("foo")
    .class("bar")
    .class("baz")
;