Dynamic attributes, attribute groups

Optional attributes

If component have many different attributes, you not always want to pass all of them. This can be done using attribute groups (AttrGroup). This is a BtreeMap of String to AttrGroupValue items. If you use it as a type in component attributes, it is automatically recognized by #[component] and dom! macro.

    use vertigo::{component, dom, AttrGroup, Value};

    #[component]
    fn MyInput(
        value: Value<String>, // required
        /// Optional attributes: id, label
        mut opt: AttrGroup,
    ) {
        let container_id = opt.remove_entry("id");

        let label = opt
            .get("label")
            .map(|label| dom! { <label>{label}</label> });

        dom! {
            <div {..container_id}>
                { ..label }
                <input value={value} />
            </div>
        }
    }

    let my_value = Value::new("John".to_string());

    dom! {
        <MyInput value={my_value} opt:id="teges" />
    }

You need to use .remove_entry because it takes the ownership of the value. Keep in mind that the value can contain a callback which is not cloneable. This also removes the attribute from the group, which is why it needs to be mutable.

Passing attribute group down to contained element

    use vertigo::{component, css, dom, AttrGroup, Value};

    #[component]
    fn MyInput(value: Value<String>, input: AttrGroup) {
        dom! {
            <div>
                <label>"First name: "</label>
                <input value={value} {..input} />
            </div>
        }
    }

    let my_value = Value::new("John".to_string());

    dom! {
        <MyInput value={my_value} input:id="first-name" input:css={css!{"color: yellow;"}} />
    }

Customizing styles using attribute group

    use vertigo::{component, css, dom, AttrGroup, Value};

    #[component]
    fn MyInput(value: Value<String>, input: AttrGroup) {
        // Base css
        let css = css!("color: red; background-color: green;");

        dom! { <input value={value} {css} {..input} /> }
    }

    let my_value = Value::new("John".to_string());

    dom! {
        <MyInput value={my_value} input:id="teges" input:css={css!{"color: yellow;"}} />
    }