Overview
Elements are the fundamental building blocks for creating user interfaces in Freya. They represent visual primitives like containers, text, and vector graphics. Every component ultimately renders elements.
Elements in Freya are similar to HTML tags or Flutter widgets - they’re the actual UI primitives that get rendered to the screen.
Core Elements
Freya provides four core elements:
rect() Generic container for layout and styling
label() Simple text rendering
paragraph() Rich text with multiple styles
svg() Vector graphics rendering
rect() - Container Element
The rect() function creates a rectangular container - the most versatile element in Freya. Think of it as a <div> in HTML or a Container in other UI frameworks.
Basic Usage
use freya :: prelude ::* ;
fn app () -> impl IntoElement {
rect ()
. width ( Size :: px ( 200 . ))
. height ( Size :: px ( 100 . ))
. background (( 255 , 0 , 0 ))
}
Layout Properties
rect() supports comprehensive layout control:
rect ()
// Size
. width ( Size :: fill ()) // Fill available space
. height ( Size :: px ( 100 . )) // Fixed height
. min_width ( Size :: px ( 200 . )) // Minimum width
. max_height ( Size :: px ( 500 . )) // Maximum height
// Spacing
. padding ( Gaps :: new_all ( 12 . )) // Inner padding
. margin ( Gaps :: new_all ( 8 . )) // Outer margin
// Direction & Alignment
. horizontal () // Horizontal layout
. center () // Center children
. spacing ( 8.0 ) // Gap between children
Vertical Layout
Horizontal Layout
Centered Layout
rect ()
. child ( rect () . height ( Size :: px ( 50 . )) . background (( 255 , 0 , 0 )))
. child ( rect () . height ( Size :: px ( 50 . )) . background (( 0 , 255 , 0 )))
. child ( rect () . height ( Size :: px ( 50 . )) . background (( 0 , 0 , 255 )))
rect ()
. horizontal ()
. child ( rect () . width ( Size :: px ( 50 . )) . background (( 255 , 0 , 0 )))
. child ( rect () . width ( Size :: px ( 50 . )) . background (( 0 , 255 , 0 )))
. child ( rect () . width ( Size :: px ( 50 . )) . background (( 0 , 0 , 255 )))
rect ()
. center ()
. width ( Size :: fill ())
. height ( Size :: fill ())
. child ( "Centered content" )
Visual Styling
rect ()
// Background
. background (( 50 , 50 , 50 )) // Solid color
. background ( Color :: RED ) // Named color
// Borders
. border ( Border :: all (( 2 . , ( 0 , 0 , 0 , 255 ))))
. corner_radius ( CornerRadius :: new ( 8 . ))
// Shadows
. shadow (( 0 . , 4 . , 20 . , 4 . , ( 0 , 0 , 0 , 80 )))
// Effects
. opacity ( 0.8 )
. blur ( 5.0 )
. rotate ( 45.0 )
. scale (( 1.2 , 1.2 ))
Text Styling (Inherited by Children)
rect ()
. color (( 255 , 255 , 255 )) // Text color
. font_size ( 16.0 ) // Font size
. font_weight ( FontWeight :: BOLD ) // Font weight
. child ( "Styled text" ) // Inherits these styles
Advanced Features
rect ()
. overflow ( Overflow :: Clip ) // Clip overflowing content
. width ( Size :: px ( 100 . ))
. height ( Size :: px ( 100 . ))
. child (
rect ()
. width ( Size :: px ( 200 . )) // Larger than parent
. height ( Size :: px ( 200 . ))
)
rect ()
. scroll_y ( true ) // Enable vertical scrolling
. height ( Size :: px ( 200 . ))
. child (
rect () . height ( Size :: px ( 1000 . )) // Content larger than container
)
rect ()
. background ( LinearGradient :: new (
vec! [
( 0.0 , Color :: RED ),
( 1.0 , Color :: BLUE ),
]
))
. width ( Size :: px ( 200 . ))
. height ( Size :: px ( 200 . ))
label() - Simple Text
The label() function renders simple text. It’s optimized for single-style text content.
Basic Usage
use freya :: prelude ::* ;
fn app () -> impl IntoElement {
label ()
. text ( "Hello, World!" )
. font_size ( 24.0 )
. color (( 255 , 0 , 0 ))
}
Freya provides convenient Into<Element> implementations for &str and String, so you can often just use strings directly: rect () . child ( "Hello!" ) // Automatically becomes a label
Text Properties
label ()
. text ( "Hello, World!" )
. font_size ( 16.0 )
. color (( 255 , 255 , 255 ))
. font_weight ( FontWeight :: BOLD )
. font_slant ( FontSlant :: Italic )
. text_align ( TextAlign :: Center )
. max_lines ( 3 )
. line_height ( 1.5 )
Text Alignment
// Left aligned (default)
label ()
. text ( "Left aligned" )
. text_align ( TextAlign :: Left )
// Center aligned
label ()
. text ( "Center aligned" )
. text_align ( TextAlign :: Center )
// Right aligned
label ()
. text ( "Right aligned" )
. text_align ( TextAlign :: Right )
Line Limits and Overflow
// Limit to 2 lines with ellipsis
label ()
. text ( "This is a very long text that will be truncated" )
. max_lines ( 2 )
. text_overflow ( TextOverflow :: Ellipsis )
paragraph() - Rich Text
The paragraph() function enables rich text with multiple styles using spans.
Basic Usage
use freya :: prelude ::* ;
fn app () -> impl IntoElement {
paragraph ()
. span ( Span :: new ( "Hello " ) . color ( Color :: RED ))
. span ( Span :: new ( "World!" ) . font_size ( 24.0 ) . font_weight ( FontWeight :: BOLD ))
}
Styling Spans
Each span can have its own styling:
paragraph ()
. span (
Span :: new ( "Bold text" )
. font_weight ( FontWeight :: BOLD )
)
. span (
Span :: new ( " Italic text" )
. font_slant ( FontSlant :: Italic )
)
. span (
Span :: new ( " Colored text" )
. color (( 255 , 0 , 0 ))
)
. span (
Span :: new ( " Large text" )
. font_size ( 24.0 )
)
Text Editor Features
Paragraphs support cursor and highlighting for text editors:
let mut cursor_index = use_state ( || 0 );
paragraph ()
. span ( Span :: new ( "Edit this text" ))
. cursor_index ( cursor_index . read ())
. cursor_color (( 0 , 0 , 255 ))
. cursor_style ( CursorStyle :: Line )
. highlights ( vec! [( 0 , 4 )]) // Highlight "Edit"
. highlight_color (( 255 , 255 , 0 , 100 ))
Line Cursor
Block Cursor
Underline Cursor
paragraph ()
. span ( Span :: new ( "Text" ))
. cursor_index ( 2 )
. cursor_style ( CursorStyle :: Line )
paragraph ()
. span ( Span :: new ( "Text" ))
. cursor_index ( 2 )
. cursor_style ( CursorStyle :: Block )
paragraph ()
. span ( Span :: new ( "Text" ))
. cursor_index ( 2 )
. cursor_style ( CursorStyle :: Underline )
Building Spans Dynamically
let words = vec! [ "Hello" , "Beautiful" , "World" ];
paragraph ()
. spans_iter (
words . into_iter () . enumerate () . map ( | ( i , word ) | {
Span :: new ( format! ( "{} " , word ))
. color ( if i % 2 == 0 { Color :: RED } else { Color :: BLUE })
})
)
svg() - Vector Graphics
The svg() function renders SVG vector graphics.
Basic Usage
use freya :: prelude ::* ;
use bytes :: Bytes ;
fn app () -> impl IntoElement {
svg ( Bytes :: from_static ( include_bytes! ( "logo.svg" )))
. width ( Size :: px ( 200 . ))
. height ( Size :: px ( 200 . ))
}
Loading SVGs
// Include SVG at compile time
svg ( Bytes :: from_static ( include_bytes! ( "../assets/icon.svg" )))
// Load SVG at runtime
let svg_data = std :: fs :: read ( "icon.svg" ) . unwrap ();
svg ( Bytes :: from ( svg_data ))
// Load from network (requires async)
let svg_data = use_resource ( || async {
reqwest :: get ( "https://example.com/icon.svg" )
. await . unwrap ()
. bytes () . await . unwrap ()
});
if let Some ( data ) = svg_data . read () . as_ref () {
svg ( data . clone ())
} else {
"Loading..."
}
Styling SVGs
svg ( bytes )
. width ( Size :: px ( 100 . ))
. height ( Size :: px ( 100 . ))
. color (( 255 , 0 , 0 )) // Override default color
. fill (( 0 , 255 , 0 )) // Override fill
. stroke (( 0 , 0 , 255 )) // Override stroke
. rotate ( 45.0 ) // Rotate the SVG
Element Comparison
Feature rect() label() paragraph() svg() Purpose Container & Layout Simple text Rich text Vector graphics Children ✅ Yes ❌ No ❌ No ❌ No Text Content ❌ No ✅ Yes ✅ Yes ❌ No Multiple Styles ❌ No ❌ No ✅ Yes ✅ Yes Layout Control ✅ Full ⚠️ Limited ⚠️ Limited ⚠️ Limited Background ✅ Yes ❌ No ❌ No ❌ No Border ✅ Yes ❌ No ❌ No ❌ No
Practical Examples
fn card ( title : & str , content : & str ) -> impl IntoElement {
rect ()
. padding ( Gaps :: new_all ( 16 . ))
. background (( 255 , 255 , 255 ))
. corner_radius ( CornerRadius :: new ( 8 . ))
. shadow (( 0 . , 2 . , 8 . , 0 . , ( 0 , 0 , 0 , 30 )))
. child (
rect ()
. child (
label ()
. text ( title )
. font_size ( 20.0 )
. font_weight ( FontWeight :: BOLD )
)
. child (
label ()
. text ( content )
. color (( 100 , 100 , 100 ))
)
)
}
fn icon_label ( icon_data : Bytes , text : & str ) -> impl IntoElement {
rect ()
. horizontal ()
. center ()
. spacing ( 8.0 )
. child (
svg ( icon_data )
. width ( Size :: px ( 24 . ))
. height ( Size :: px ( 24 . ))
)
. child ( label () . text ( text ))
}
fn search_result ( text : & str , query : & str ) -> impl IntoElement {
// Find query position
let start = text . find ( query ) . unwrap_or ( 0 );
let end = start + query . len ();
paragraph ()
. span ( Span :: new ( & text [ .. start ]))
. span (
Span :: new ( & text [ start .. end ])
. background (( 255 , 255 , 0 ))
. font_weight ( FontWeight :: BOLD )
)
. span ( Span :: new ( & text [ end .. ]))
}
Best Practices
Choose the right element
Use rect() for layout and containers
Use label() for simple text
Use paragraph() for styled text
Use svg() for icons and vector graphics
Optimize text rendering
Prefer label() over paragraph() when you don’t need multiple styles - it’s more efficient.
Use string shortcuts
// Instead of:
rect () . child ( label () . text ( "Hello" ))
// Use:
rect () . child ( "Hello" )
Preload assets
For SVGs and images, use include_bytes!() to embed them at compile time for faster loading.
Next Steps
Components Build reusable components with elements
Events Make elements interactive
Layers Control rendering order
State Management Add dynamic behavior