API

Learn how to define custom APIs for widgets and components in LVGL Pro Editor with properties, parameters, and elements.

The <api> tag can be a child of <widget> and <component> tags. Screens don't support custom APIs.

Both Widgets and Components support having <prop> (properties) in the <api> tag to describe their interface. However, since Widgets and Components work very differently — Widgets have C code while Components are pure XML — properties are interpreted differently in each context.

Components

Overview

While Widgets can have complex set/get APIs, Components are very simple.

When a component's XML is converted to C files, only a create function is generated, where all the props are arguments. For example:

xml
<api>
  <prop name="prop1" type="int"/>
  <prop name="prop2" type="string"/>
</api>

Referencing Properties

Props are simply forwarded to Widget or Component APIs. For example, if a component has <prop name="button_label" type="string"/>, it can be used in a label child as <lv_label text="$button_label"/>.

In the code generated by LVGL's UI Editor, these are passed as arguments in create/set functions.

Default Values

Since each property is passed as an argument to the create function, each must have a value. This can be ensured by:

  • Simply setting them in the XML instance
  • Providing a default value in the api, for example: <prop name="title" type="string" default="my_default_text"/>

Code Generation

LVGL's UI Editor can generate code from the component's XML. Depending on the api, a function like this is generated:

 
lv_obj_t * my_component_create(lv_obj_t * parent, int32_t prop1, const char * prop2);

These properties are set once at creation time, and there are no specific set functions to modify the property later. LVGL's general API can still be used to modify any widget in the component, but no dedicated API functions are generated.

Slots

With the help of a "slot," any UI element in the component can be easily exposed as a parent where children can be created later.

Add <slot name="my_slot"/> to the api to tell the Editor which children to expose.

To target a slot on an instance of a component, create a child like <component_name-slot_name> and add the children as needed.

Slots are available only for components. For widgets, the more powerful elements with get access type can be used instead.

Slots are very useful for creating components like screen templates where users are allowed to create children on certain internal UI elements.

Slots Example

xml
<!-- simple_screen.xml -->
<component>
  <api>
    <slot name="icon_area"/>
    <slot name="content_area"/>
  </api>

  <view width="100%" height="100%" flex_flow="column">
    <lv_obj name="icon_area" width="100%" height="30" flex_flow="row"/>
    <lv_obj name="content_area" width="100%" flex_grow="1" flex_flow="column"/>
  </view>
</component>

<!-- main_screen.xml -->
<component>
  <view extends="simple_screen" width="100%">
    <simple_screen-icon_area>
      <lv_image src="img1"/>
      <lv_image src="img2"/>
    </simple_screen-icon_area>

    <simple_screen-content_area>
      <lv_label text="Some content"/>
    </simple_screen-content_area>
  </view>
</component>

Limitations

Component APIs support only simple properties that are forwarded. The following Widget API features cannot be used for Components:

  • param - Parameters
  • enumdef - Enum definitions
  • element - Sub-widgets or internal structures

Widgets

Properties

Properties are the core part of describing a Widget's API.

xml
<api>
  <prop name="text" type="string" help="Text of the label."/>
</api>

Parameters

Some properties take multiple parameters. For example:

 
lv_label_set_bind_text(label, subject, "%d °C")

This is described as:

xml
<api>
  <prop name="bind_text" help="Bind a subject's value to a label.">
    <param name="bind_text" type="subject" help="Integer or string subject"/>
    <param name="fmt" type="string" help="Format string, e.g. %d °C"/>
  </prop>
</api>

And used in XML as:

xml
<lv_label bind_text="subject" bind_text-fmt="%d °C"/>

Parameters with the same name as the property can be referenced directly. Other parameters use property-param notation.

Unset parameters fall back to:

  • Their default value (if defined)
  • Type-specific defaults (e.g., 0, false, NULL)

Mapping Properties to Functions

Each prop is mapped to a set function. This mapping is implemented in the Widget's XML parser. See the LVGL XML parsers.

If params are used, they are passed to the same set function. If a property is not set on a Widget instance, it is skipped and the Widget's built-in default is used.

Enum Definitions

Only used with Widgets, this tag defines enums for parameter values.

xml
<api>
  <enumdef name="my_widget_mode" help="Possible modes">
    <enum name="normal" help="Normal mode" value="0x10"/>
    <enum name="inverted" help="Inverted mode"/>
  </enumdef>
  <prop name="mode" help="Set Widget mode">
    <param name="mode" type="enum:my_widget_mode"/>
  </prop>
</api>

The actual values of the enum fields are not important during code export because only the names are used and resolved by the compiler. XML parsers must handle mapping enum string names (for example, "normal") to C enums (for example, MY_WIDGET_MODE_NORMAL).

Elements

Also exclusive to Widgets, elements define sub-widgets or internal structures (for example, chart series, dropdown lists, tab views).

Elements are also very useful to create "slots" (similar to tabview tabs), like a content and header area for a window widget, where children can be created directly.

Elements are described inside the api tag and can have arg and prop children:

  • args are required and used when creating/getting the element
  • props are optional and mapped to setters

Here's an example to define an "indicator" that can be added dynamically to a widget. It will create my_indicator_t * elements the same way as, for example, lv_chart_add_series works:

xml
<api>
  <element name="indicator" type="my_indicator_t" help="The indicator of my_widget" access="add">
    <!-- args are passed when the element is created -->
    <arg name="color" type="color"/>
    <arg name="max_value" type="int"/>

    <!-- props can be set by setters at any time -->
    <prop name="value" type="int"/>
  </element>
</api>

Element Access Types

Element access types control how elements are created and accessed:

  • add - Create multiple elements dynamically (for example, tabview tabs)
  • get - Access implicitly created elements (for example, dropdown lists)
  • set - Access indexed parts (for example, table cells)
  • custom - Map custom C functions to XML (for example, bind_state_is_eq)

Element Types and Return Values

As add and get elements return an object, they also have a type. This type can be any custom type, for example, type="my_data". In the exported code, the return value will be saved in a my_data_t * variable.

If the type is type="lv_obj", the element can have child widgets or components.

Element Naming and Implementation

Elements are referenced as <widget-element> in the view. The parts of the name are separated by -. Since - is not allowed inside names, it's safe to use as a separator.

Note that only the API can be defined in XML for elements. The implementation must be in C.

access="add"

Elements are created via an add function:

xml
<api>
  <element name="indicator" type="obj" help="The indicator of my_widget" access="add">
    <arg name="color" type="color"/>
    <arg name="max_value" type="int"/>
    <prop name="value">
      <param name="value" type="int"/>
    </prop>
  </element>
</api>

Used in a view:

xml
<view>
  <my_widget width="100px">
    <my_widget-indicator name="indic1" color="0xff0000" max_value="120" value="30"/>
  </my_widget>
</view>  

LVGL's UI Editor generates:

 
lv_obj_t * my_widget_add_indicator(lv_obj_t * parent, lv_color_t color, int32_t max_value);
void my_widget_set_indicator_value(lv_obj_t * obj, int32_t value);

access="get"

Used for internal or implicit elements:

xml
<api>
  <element name="control_button" type="obj" help="A control button of my_widget" access="get">
    <arg name="index" type="int"/>
    <prop name="title" type="string"/>
  </element>
</api>

Used in a view:

xml
<view>  
  <my_widget width="100px">
    <my_widget-control_button name="btn1" index="3" title="Hello"/>
  </my_widget>
</view>  

LVGL's UI Editor generates:

 
lv_obj_t * my_widget_get_control_button(lv_obj_t * parent, int32_t index);
void my_widget_set_control_button_title(lv_obj_t * obj, const char * text);

access="set"

Used for indexed access, like setting values in a table:

xml
<api>
  <element name="item" type="obj" access="set">
    <arg name="index" type="int"/>
    <prop name="icon" type="img_src"/>
    <prop name="color" type="color"/>
  </element>
</api>

Used in a view:

xml
<view>  
  <my_widget width="100px">
    <my_widget-item index="3" icon="image1" color="0xff0000"/>
  </my_widget>
</view>  

LVGL's UI Editor generates:

 
void my_widget_set_item_icon(lv_obj_t * parent, int32_t index, const void * icon_src);
void my_widget_set_item_color(lv_obj_t * parent, int32_t index, lv_color_t color);

access="custom"

Used to describe custom API functions with a custom name. Custom elements can have only arguments and no type, so they are pure setters.

xml
<element name="bind_color" access="custom">
  <arg name="subject" type="subject"/>
  <arg name="new_color" type="color"/>
  <arg name="ref_value" type="int"/>
</element>

Used in a view:

xml
<view>  
  <my_widget width="100px">
    <my_widget-bind_color subject="subject_1" new_color="0xff0000" ref_value="15"/>
  </my_widget>
</view>  

LVGL's UI Editor generates:

 
void my_widget_bind_color(lv_obj_t * parent, lv_subject_t * subject, lv_color_t color, int32_t ref_value);

How is this guide?

Last updated on

On this page