Evaluate expressions

Compute attribute values from arithmetic, comparisons, ternaries, and string concatenation directly in your XML.

This feature requires LVGL Pro Editor v2.0 or higher.

Any XML attribute value can be an expression wrapped in { }. Instead of writing a fixed value, you let the Editor compute it from numbers, colors, strings, constants, and parameters.

xml
<lv_obj width="{base_width * 2}"/>
<lv_label text="{'Hello, ' . user_name . '!'}"/>
<lv_obj hidden="{item_count == 0}"/>

Overview

Expressions are useful whenever a value is derived from other values: a width that is twice a parameter, a label that joins a prefix with a name, a flag that depends on a count, and so on. Keeping the calculation in the XML means you don't have to duplicate or pre-compute values by hand.

A few important properties to keep in mind:

  • Creation-time only. An expression is evaluated once, when the UI element is created. The result is then handed to the normal attribute parser exactly as if you had typed the computed value yourself.
  • Not data binding. Expressions do not react to changes. If you need a value that updates at runtime when a subject changes, use data binding instead.
  • The result type is inferred from the terms. You never declare the type — it follows from the literals and variables you use (see Value types).

Expressions are exported into the generated C code, not pre-computed to a fixed literal. They are re-evaluated every time the element is created — including when you create a component manually from C — using the parameter values passed at that moment.

Writing expressions

An expression is the whole attribute value, wrapped in a single pair of braces:

xml
<lv_obj width="{10 + 20}"/>   <!-- becomes width="30" -->

Inside the braces you can use literals, operators, and variable names. A variable name is written as a bare identifier — without the $ or # prefixes used elsewhere in XML. The name is resolved, in order, against:

  1. Parameters declared in the element's <api> — the value comes from the instance (or the parameter's default), and the type from the declared type.
  2. Constants from <consts> — the type is inferred from the constant's value.
  3. Other named items the XML processor resolves later (a font, image, subject, or screen name). These are passed through as plain strings.
xml
<component>
  <consts>
    <int name="gap" value="8"/>
  </consts>
  <api>
    <prop name="columns" type="int" default="3"/>
  </api>

  <view>
    <!-- `gap` is a const, `columns` is a param -->
    <lv_obj width="{columns * 100 + (columns - 1) * gap}"/>
  </view>
</component>

Note that $ and # are not used in expressions to reference properties and constants.

Value types

Each term has a type, inferred from how it is written:

TermExampleType
Decimal integer42int
Number with a fraction3.5float
Hex literal0xff0000, 0xf00color
Single-quoted text'hello'string
true / falsetruebool
A comparisona == bbool
A variablemy_paramits own type

Notes:

  • Colors accept both the full 0xRRGGBB form and the 0xRGB shorthand, which expands like CSS (0xf00 → 0xff0000).
  • Strings use single quotes ('…'), since double quotes already delimit the XML attribute.
  • Floats require LV_USE_FLOAT. Without it, a float degrades to its integer part. Float results are serialized with two decimals (e.g. 3.50).

Operators

Arithmetic

+, -, *, /, % operate on numbers. % requires integer operands, and division or modulo by zero is an error.

xml
<lv_obj width="{100 + pad * 2}"/>
<lv_obj height="{total / 3}"/>

Comparison

== and != work on any two operands of the same type (numbers, strings, colors, or bools). The ordered comparisons <, <=, >, >= work on numbers only. Every comparison yields a bool.

xml
<lv_obj hidden="{count == 0}"/>
<lv_obj checked="{mode == 'dark'}"/>

Only one comparison is allowed per expression — comparisons cannot be chained (a < b < c is invalid).

Logical not

The unary ! accepts a number, bool, or string and returns a bool. An empty or missing string is falsy (like a NULL pointer in C).

xml
<lv_obj clickable="{!locked}"/>

There are intentionally no &&, ||, or ^^ operators.

Ternary

cond ? a : b chooses between two values. The condition must be a bool, a number, or a string (a non-empty string is truthy); it cannot be a color. Both branches must have the same type (int and float mix freely).

xml
<lv_label text="{count == 0 ? 'Empty' : 'Has items'}"/>
<lv_obj style_bg_color="{is_on ? 0x00ff00 : 0x333333}"/>

Ternaries cannot be nested, but each branch may itself be a string concatenation.

String concatenation

The . operator joins values into a single string. Each operand is automatically stringified — integers and floats as decimals, bools as true/false, colors as 0xRRGGBB.

xml
<lv_label text="{'Battery: ' . level . '%'}"/>
<lv_label text="{first_name . ' ' . last_name}"/>

Precedence and grouping

From highest to lowest:

  1. Unary -, +, !
  2. *, /, %
  3. +, -
  4. Comparisons (==, !=, <, <=, >, >=)
  5. Concatenation (.)
  6. Ternary (? :)

Parentheses ( ) group arithmetic and comparison sub-expressions. They cannot contain a concatenation or a ternary.

xml
<lv_obj width="{(a + b) * 2}"/>

Error handling

If an expression is malformed — an unknown identifier, a type mismatch, a missing ) or :, division by zero, and so on — evaluation fails. A warning describing the exact problem and the offending expression is logged, and the attribute is left unset.

Common messages include:

  • unknown identifier — the name is not a const, or prop.
  • the two ternary branches must have the same type.
  • < <= > >= need numeric operands — use ==/!= for strings, colors, and bools.
  • arithmetic + - * / % needs numeric operands.
  • unexpected character (note: use == to compare, . to concatenate).

Examples

xml
<!-- Arithmetic with a constant and a parameter -->
<lv_obj width="{card_width * column_count + gap * (column_count - 1)}"/>

<!-- Conditional text -->
<lv_label text="{unread == 0 ? 'No new messages' : 'New messages'}"/>

<!-- Building a string from several parts -->
<lv_label text="{'Room ' . room_id . ': ' . temperature . ' °C'}"/>

<!-- Boolean flag from a comparison -->
<lv_obj hidden="{progress >= 100}"/>

<!-- Color chosen by a flag -->
<lv_obj style_bg_color="{active ? 0x2e7d32 : 0x9e9e9e}"/>

Last updated on

On this page