Rendering your own types
As a text: DomDisplay
Numbers and strings can be put into dom! as they are. A type of your own, even if it implements Display, has to opt in with DomDisplay:
use vertigo::{dom, DomDisplay, Value}; #[derive(Clone, PartialEq)] struct Money { cents: u64, } impl std::fmt::Display for Money { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "${}.{:02}", self.cents / 100, self.cents % 100) } } // Allows to use Money in `dom!` as a text and as an attribute value impl DomDisplay for Money {} let price = Money { cents: 1999 }; let balance = Value::new(Money { cents: 50000 }); dom! { <div> <p title={&price}>"Price: " {&price}</p> <p>"Balance: " {balance}</p> </div> }
That one line covers the value and references to it, both as a text and as an attribute value. Value and Computed of a type implementing Display can be embedded as a text even without it.
If the type comes from another crate, you can't implement DomDisplay for it. Pass value.to_string() or wrap the value in a type of your own. Date and time types from chrono and Decimal from rust_decimal are already supported, when chrono or rust_decimal feature of vertigo is enabled.
As a DOM: EmbedDom
A type can also render itself into real DOM, by implementing EmbedDom:
use vertigo::{css, dom, DomNode, EmbedDom}; struct Badge { label: String, count: u32, } // Allows to put a Badge directly into `dom!` impl EmbedDom for Badge { fn embed(self) -> DomNode { let css = css! {" padding: 2px 6px; border-radius: 8px; background-color: #e07020; "}; dom! { <span {css}>{self.label} " " {self.count}</span> } } } let inbox = Badge { label: "Inbox".to_string(), count: 3, }; dom! { <nav>{inbox}</nav> }
A type can implement either DomDisplay or EmbedDom, not both.