Dynamic attributes, attribute groups
Optional attributes
If a component has many different attributes, you don't 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" /> }
.remove_entry returns the key together with the value, which is just what spreading {..container_id} needs. It also removes the attribute from the group (that's why the group needs to be mutable), so it won't be applied twice if you spread the rest of the group onto another element. If you'd rather keep the group intact, AttrGroupValue can be cloned as well - callbacks inside are kept in Rc.
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;"}} /> }