Skip to content
Layout & Styling

Layout & Styling

Layout containers

// Horizontal flex
hbox {
    gap 8; align-items "center"
    label "Left"
    label "Right"
}

// Vertical flex
vbox {
    gap 8; padding 16
    label "Top"
    label "Bottom"
}

// Plain container (no flex direction)
box {
    width 200; height 100
    label "Centered" { align "center" }
}

// CSS-style grid
grid {
    columns "100 1fr 1fr"; rows "40 1fr"
    gap 8
    label "Header" { grid-cell "0,0,3,1" }  // span 3 columns
    label "Sidebar" { grid-cell "0,1" }
    label "Main" { grid-cell "1,1" }
}

Grid tracks accept fixed pixels (100), fractions of remaining space (1fr), and content.

Flex properties

PropertyValues
flex-flowrow, column, row-wrap, column-wrap, reverse variants
flex-growinteger grow factor
gappixels between children
justifycenter, space-between, space-around, space-evenly
align-itemscenter, start, end

A classic header / content / footer skeleton:

vbox {
    fill #true; padding 16
    hbox { fill-width #true; height 40; /* header */ }
    vbox { fill-width #true; flex-grow 1; /* main content */ }
    hbox { fill-width #true; height 30; /* footer */ }
}

Sizing and positioning

Widths and heights take pixels, percentages ("50%"), or "content". fill, fill-width, and fill-height expand to the parent.

label "Center" { align "center" }
label "With offset" { align "center,10,20" }   // center + 10px right, 20px down

Alignment values: center, top-left, top-mid, top-right, bottom-left, bottom-mid, bottom-right, left-mid, right-mid, optionally with ,x,y pixel offsets.

Elements can also float above the normal layout:

box {
    width 200; height 100
    label "Content" { align "center" }
    label "!" {
        floating #true; align "top-right"
        bg-color "#E94560"; bg-opa 255; radius "circle"
        width 20; height 20; text-align "center"
    }
}

Other layout flags: ignore-layout, new-track (break to a new flex line), scrollable, overflow-visible, clickable, hidden (bindable).

Named styles

Define once, apply anywhere. Multiple styles stack:

style "card" {
    bg-color "#2D2D2D"
    bg-opa 255
    radius 12
    padding 16
}

vbox {
    style "card"
    style "shadow"
    label "Styled content"
}

State variants

Styles can vary by interactive state: pressed, focused, checked, disabled:

style "btn" {
    bg-color "#333333"; bg-opa 255; radius 8
}
style "btn" state="pressed" {
    bg-color "#555555"
}

Style transitions

Property changes between states can animate:

style "card" {
    bg-color "#2D2D2D"; bg-opa 255
    transition "bg-color" duration=200
    transition "bg-opa" duration=200 delay=50
}
style "card" state="pressed" {
    bg-color "#3D3D3D"
}

Spacing, colors, borders

vbox {
    padding 16               // all sides; -top/-bottom/-left/-right,
    padding-hor 12           // and -hor/-ver shorthands available
    margin-top 4
}

box {
    bg-color "#16213E"; bg-opa 255
    text-color "#FFFFFF"
    border-width 2; border-color "#444444"; border-side "bottom"
    shadow-width 8; shadow-color "#000000"; shadow-opa 128
    radius 12                // or "circle"
    opa 200                  // whole-widget opacity
}

Scroll behavior

Snap scrolling

scroll-snap-x/scroll-snap-y on a container plus snappable children make paged or selector-style scrolling:

vbox {
    scrollable #true
    scroll-dir "vertical"
    scroll-snap-y "center"
    scroll-one #true                // stop after one snap point
    scrollbar-mode "off"

    box { snappable #true; height 60 }
    box { snappable #true; height 60 }
    box { snappable #true; height 60 }
}

Add page-indicator #true to a horizontally snapping container to get page dots that track the scroll position.

Behavior flags and scrollbars

box {
    scroll-momentum #false          // disable inertial scrolling
    scroll-elastic #false           // disable rubber-band overscroll
    scroll-chain #false             // don't propagate to parent

    scrollbar-mode "auto"           // off, on, active, auto
    scrollbar-width 4
    scrollbar-bg-color "#333333"
}

Transforms

box {
    transform-scale 256              // 256 = 1x, 512 = 2x
    transform-rotation 450           // 0.1-degree units (450 = 45°)
    transform-pivot-x 50
    transform-pivot-y 50
}

Transforms are animatable. See Animations.

Text and fonts

label "Hello" {
    text-font "montserrat_18"       // built-in font
    text-align "center"
    text-color "#FFFFFF"
    text-line-space 4
}

Built-in Montserrat sizes range from 12 to 28. Custom fonts are registered from firmware code and referenced by name. See Advanced → Assets.