Text and Typography
Text is fundamental to any UI framework. WaterUI provides two distinct approaches for displaying text: labels for static text without styling, and the Text component for reactive text with rich styling capabilities.
Understanding Labels vs Text Components
Labels: Simple Static Text
In WaterUI, several types implement the View
trait directly and are called "labels":
&'static str
- String literalsString
- Owned stringsStr
- WaterUI's optimized string type
Labels are rendered as simple, unstyled text and are perfect for static content:
#![allow(unused)] fn main() { use waterui::View; use waterui::component::layout::stack::vstack; fn label_examples() -> impl View { vstack(( // String literal as label "Simple static text", // String variable as label String::from("Dynamic string as label"), // Multi-line text r#"Multi-line text with line breaks"#, )) } }
Text Component: Reactive and Styleable
The Text
component provides reactive updates and rich styling options:
#![allow(unused)] fn main() { use waterui::View; use waterui::reactive::binding; use waterui::component::layout::stack::vstack; use waterui::component::button::button; use waterui_text::{text, Text}; fn text_component_examples() -> impl View { let count = binding(0); let name = binding("Alice".to_string()); vstack(( // Basic Text component "Styleable text content", // Reactive text with text! macro text!("Count: {}", count), text!("Hello, {}!", name), // Text component with styling Text::new("Styled text").size(20.0), button("Increment") .action({ let count = count.clone(); move |_| count.update(|c| c + 1) }), )) } }
Text Styling with the Text Component
Only the Text
component (created with text()
function or Text::new()
) supports styling. Labels (&str
, String
, Str
) are rendered without styling.
Font Properties
#![allow(unused)] fn main() { use waterui::View; use waterui::component::layout::stack::vstack; use waterui_text::text; fn font_styling_demo() -> impl View { vstack(( // Labels - no styling available "Default label text", // Text components - styling available text("Large text") .size(24.0), text("Small text") .size(12.0), // Bold/weight not yet available text("Styleable text").size(18.0), )) } }
When to Use Labels vs Text Components
Choose the right approach based on your needs:
#![allow(unused)] fn main() { use waterui::View; use waterui::component::layout::stack::vstack; use waterui_text::text; fn choosing_text_type() -> impl View { vstack(( // Use labels for simple, static text "Static heading", "Simple description text", // Use Text component for styled text text("Styled heading").size(20.0), // Use text! macro for reactive content { let count = binding(42); text!("Dynamic count: {}", count) }, )) } }
Reactive Text with the text! Macro
The text!
macro creates reactive Text components that automatically update when underlying data changes:
#![allow(unused)] fn main() { use waterui::View; use waterui::reactive::{binding, s}; use waterui::component::layout::stack::{vstack, hstack}; use waterui::component::button::button; use waterui_text::text; fn reactive_text_demo() -> impl View { let count = binding(0); let name = binding(String::from("Alice")); let temperature = binding(22.5); vstack(( // Reactive formatted text text!("Count: {}", count), text!("Hello, {}!", name), text!("Temperature: {:.1}°C", temperature), // Reactive with computed expressions using s! macro text!("Status: {}", s!(if count > 5 { "High" } else { "Low" })), hstack(( button("Increment").action({ let count = count.clone(); move |_| count.update(|c| c + 1) }), button("Reset").action({ let count = count.clone(); move |_| count.set(0) }), )), )) } }
Formatting Best Practices
Always use text!
macro for reactive text, never format!
macro which loses reactivity:
#![allow(unused)] fn main() { use waterui::View; use waterui::component::layout::stack::vstack; use waterui::reactive::binding; use waterui_text::text; fn formatting_best_practices() -> impl View { let user_count = binding(42); let status = binding(String::from("Active")); vstack(( // ✅ CORRECT: Use text! for reactive content text!("Users: {} ({})", user_count, status), // ❌ WRONG: .get() breaks reactivity! // text(format!("Users: {} ({})", user_count.get(), status.get())) // This creates static text that won't update when signals change! // ✅ CORRECT: Use labels for static text "Status Dashboard", // ✅ CORRECT: Use text() for static styleable content text("Styleable heading").size(18.0), )) } }
Advanced Text Component Features
The Text component provides additional capabilities beyond basic labels:
Text Display Options
#![allow(unused)] fn main() { use waterui::View; use waterui::component::layout::stack::vstack; use waterui::reactive::binding; use waterui_text::{text, Text}; fn text_display_demo() -> impl View { vstack(( // Display formatting with different value types Text::display(binding(42)), Text::display(binding(3.14159)), Text::display(binding(true)), // Custom formatting with formatters { let price = binding(29.99); Text::format(price, |value| format!("${:.2}", value)) }, )) } }
// Rich text (spans, bold/italic) is planned but not yet available.
Performance Considerations
Efficient Reactive Updates
#![allow(unused)] fn main() { use waterui::View; use waterui::component::layout::stack::vstack; use waterui::component::button::button; use waterui::reactive::{binding, s}; use waterui_text::text; fn efficient_text_updates() -> impl View { let counter = binding(0); vstack(( // ✅ GOOD: Reactive text with text! macro text!("Counter: {}", counter), // ✅ GOOD: Computed reactive text text!("Status: {}", s!(match counter { 0..=10 => "Low", 11..=50 => "Medium", _ => "High" })), button("Increment").action({ let counter = counter.clone(); move |_| counter.update(|c| c + 1) }), )) } }
Summary
WaterUI's text system provides:
- Labels (
&str
,String
,Str
): Simple, unstyled text for static content - Text Component: Reactive, styleable text with font customization
- text! macro: Reactive formatted text that updates automatically
- Font API: Comprehensive typography control for Text components
Key Guidelines
- Use labels for simple, static text without styling
- Use Text component when you need styling or reactive updates
- Use text! macro for formatted reactive content
- Never use
format!
with reactive values - it breaks reactivity - Choose the simplest approach that meets your needs
Quick Reference
#![allow(unused)] fn main() { use waterui::View; use waterui::component::layout::stack::vstack; use waterui::reactive::binding; use waterui_text::{text, Text}; fn text_reference() -> impl View { let count = binding(42); vstack(( // Label: static, no styling "Simple text", // Text: static, with styling text("Styled text").size(18.0), // Text: reactive, formatted text!("Count: {}", count), // Text: reactive, custom formatting Text::display(count), Text::format(count, |n| format!("#{:03}", n)), )) } }
Next: Forms