Skip to main content

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
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)))

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))
paragraph()
    .span(Span::new("Text"))
    .cursor_index(2)
    .cursor_style(CursorStyle::Line)

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")))

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

Featurerect()label()paragraph()svg()
PurposeContainer & LayoutSimple textRich textVector 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

1

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
2

Optimize text rendering

Prefer label() over paragraph() when you don’t need multiple styles - it’s more efficient.
3

Use string shortcuts

// Instead of:
rect().child(label().text("Hello"))

// Use:
rect().child("Hello")
4

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

Build docs developers (and LLMs) love