Skip to main content

Widgets

Egern supports iOS Widgets, allowing users to display custom content on the Home Screen and Lock Screen. Widgets are rendered from a JSON-based DSL description generated by JavaScript scripts.

Widget Configuration

Define widgets in the widgets field of the main configuration file:

  • name (string), required

    The widget name, must be unique.

  • script_name (string), optional

    The name of an associated generic script. Defaults to using a script with the same name as the widget.

  • env (object), optional

    Environment variables (key-value pairs) passed to the script. See Environment Variables for details.

Configuration Example

scriptings:
- generic:
name: "weather-widget"
script_url: "https://example.com/scripts/weather.js"
timeout: 20
- generic:
name: "net-status-script"
script_url: "https://example.com/scripts/net-status.js"
timeout: 20

widgets:
# name matches script name, no need to set script_name
- name: "weather-widget"
env:
CITY: "Shanghai"
UNIT: "celsius"
# name differs from script name, use script_name to specify the associated script
- name: "network-monitor"
script_name: "net-status-script"

Widget DSL

A widget script is a generic type script that returns a JSON-based DSL description via return. The DSL uses a tree structure composed of nested elements.

Script Context

The following properties are available on the ctx object during widget script execution:

VariableDescription
ctx.widgetFamilyWidget size family
ctx.envEnvironment variables as key-value pairs

Widget Families:

ValueDescription
systemSmallHome Screen small
systemMediumHome Screen medium
systemLargeHome Screen large
systemExtraLargeHome Screen extra large (iPad)
accessoryCircularLock Screen circular
accessoryRectangularLock Screen rectangular
accessoryInlineLock Screen inline

Element Types (type)

ValueDescription
widgetRoot container, must be the outermost element. Uses vertical layout internally
stackFlex container, supports horizontal / vertical direction
textText
imageImage (SF Symbol or Base64 image)
spacerFlexible / fixed spacing
dateReal-time date/time display (automatically updated by the system)

Common Properties

PropertyTypeApplies toDescription
urlstringwidget, stack, text, image, dateURL to open on tap (deep link or web URL)
opacitynumbertext, image, dateOpacity, 0.01.0, default 1.0
widthnumberstack, imageElement width, 0 or unset means no constraint
heightnumberstack, imageElement height, 0 or unset means no constraint
flexnumberAll elementsFlex ratio. Distributes remaining space proportionally among flex children in the parent container
paddingnumber | [top, right, bottom, left]widget, stackInner padding. A single number applies equally to all sides; an array specifies each side in CSS clockwise order
gapnumberwidget, stackSpacing between children, default 0
backgroundColorColorwidget, stackBackground color
backgroundGradientGradientwidget, stackBackground gradient, takes priority over backgroundColor
backgroundImagestringwidget, stackBackground image data URI (e.g. "data:image/png;base64,..."), highest priority
borderRadiusnumber | "auto"stack, imageCorner radius. Set to "auto" to automatically match the widget container's corner shape
borderWidthnumberstack, imageBorder width
borderColorColorstack, imageBorder color
shadowColorColortext, image, date, stackShadow color
shadowRadiusnumbertext, image, date, stackShadow blur radius (must be set for shadow to take effect)
shadowOffsetPointtext, image, date, stackShadow offset {x, y}, default {0, 0}

widget (Root Container)

The root container defaults to vertical layout, with children arranged top-to-bottom and aligned to the top-left.

PropertyTypeDescription
refreshAfterstringISO 8601 time indicating when the widget should refresh
{
"type": "widget",
"children": [ ... ],
"gap": 8,
"padding": 16,
"backgroundColor": "#1A1A2E"
}

stack (Flex Container)

PropertyTypeValuesDescription
directionstring"row", "column"Layout direction, default "row"
alignItemsstringSee table belowCross-axis alignment, default "center"
children[Element]Array of child elements

alignItems values:

ValueMeaning in row stackMeaning in column stack
"start"Children align to topChildren align to left
"end"Children align to bottomChildren align to right
"center"Children vertically centeredChildren horizontally centered
{
"type": "stack",
"direction": "row",
"alignItems": "center",
"gap": 6,
"children": [
{"type": "text", "text": "CPU"},
{"type": "spacer"},
{"type": "text", "text": "42%"}
]
}

text

PropertyTypeDescription
textstringText content to display, supports \n for line breaks
fontFontFont configuration
textColorColorText color, defaults to the system primary color
textAlignstringText alignment: "left" (default), "center", "right"
maxLinesnumberMaximum number of lines
minScalenumberMinimum text scale factor (0.01.0), used for adaptive shrinking
{
"type": "text",
"text": "Hello, Widget!",
"font": {"size": "title2", "weight": "semibold"},
"textColor": "#FFFFFF",
"maxLines": 1,
"minScale": 0.5
}

image

The src property specifies the image source, supporting two URI schemes:

  • SF Symbolsf-symbol:<name>, e.g. "sf-symbol:wifi"
  • Base64 imagedata:<mime>;base64,<data>, e.g. "data:image/png;base64,iVBORw0KGgo..."
PropertyTypeDescription
srcstringImage source URI
colorColorSF Symbol tint color (only applies to SF Symbols)
resizeModestring"contain" (default) or "cover"
resizablebooleanWhether resizable. Set to false to use original size, default true (auto-enabled when width/height are set)

When src is not provided or the URI cannot be parsed, a placeholder icon will be displayed.

{
"type": "image",
"src": "sf-symbol:wifi",
"width": 16,
"height": 16,
"color": "#FFFFFF"
}
{
"type": "image",
"src": "data:image/png;base64,iVBORw0KGgo...",
"width": 40,
"height": 40,
"resizeMode": "cover",
"borderRadius": 8
}

spacer

PropertyTypeDescription
lengthnumberFixed length. When omitted, acts as a flexible spacer that fills remaining space
{"type": "spacer"}
{"type": "spacer", "length": 10}

date

The system updates the date display in real time without requiring a widget refresh.

PropertyTypeDescription
datestringISO 8601 date string, e.g. "2026-03-04T12:00:00Z"
formatstringDisplay style, see table below. Default "date"
fontFontFont configuration
textColorColorText color
textAlignstringText alignment: "left" (default), "center", "right"
maxLinesnumberMaximum number of lines
minScalenumberMinimum scale factor

format values:

ValueDescriptionExample Output
"date"DateMarch 4, 2026
"time"Time12:00 PM
"relative"Relative time2 hours ago
"offset"Offset+2 hours
"timer"Timer2:30:15
{
"type": "date",
"date": "2026-03-04T12:00:00Z",
"format": "relative",
"font": {"size": "caption1", "weight": "medium"},
"textColor": "#FFFFFFDD"
}

Compound Type Definitions

Color

Colors support two modes:

Fixed color — use a string directly:

"textColor": "#FF5733"
"textColor": "#FF573380"
"textColor": "rgba(255, 87, 51, 1.0)"

Adaptive color — automatically switches between light/dark mode:

"textColor": {"light": "#000000", "dark": "#FFFFFF"}

Supported color formats:

FormatExampleDescription
6-digit Hex#RRGGBBOpaque color
8-digit Hex#RRGGBBAAWith alpha (last two digits)
rgba()rgba(R, G, B, A)R/G/B: 0–255, A: 0.0–1.0

Font

{"size": "headline", "weight": "bold"}
{"size": 14, "weight": "bold"}
{"size": 14, "weight": "bold", "family": "Menlo"}

All fields are optional. When omitted, defaults to body style.

size: Supports semantic style names (string, dynamically scales with system font size) or exact numeric values (number).

Semantic StyleDefault Size
"largeTitle"34
"title"28
"title2"22
"title3"20
"headline"17
"body"17
"callout"16
"subheadline"15
"footnote"13
"caption1"12
"caption2"11

weight: "ultraLight", "thin", "light", "regular", "medium", "semibold", "bold", "heavy", "black"

family: Custom font name (e.g. "Menlo"). When using family, you must also specify size to determine the font size.

Gradient

{
"type": "linear",
"colors": ["#1A1A2E", "#16213E", "#0F3460"],
"stops": [0, 0.5, 1.0],
"startPoint": {"x": 0, "y": 0},
"endPoint": {"x": 1, "y": 1}
}

type: "linear" (default), "radial", "angular"

Common properties:

PropertyTypeDescription
colors[Color]Array of gradient colors (required)
stops[number]Position of each color 0.0–1.0, count must match colors

Linear-specific properties:

PropertyTypeDefaultDescription
startPointPoint{x: 0, y: 0}Start point (top-left)
endPointPoint{x: 1, y: 1}End point (bottom-right)

Radial-specific properties:

PropertyTypeDefaultDescription
centerPoint{x: 0.5, y: 0.5}Center point
startRadiusnumber0Start radius
endRadiusnumber100End radius

Angular-specific properties:

PropertyTypeDefaultDescription
centerPoint{x: 0.5, y: 0.5}Center point
startAnglenumber0Start angle (degrees)
endAnglenumber360End angle (degrees)

Point

{"x": 0.5, "y": 0.5}

flex (Flex Layout)

When child elements have the flex property set, the parent container (widget or stack) distributes remaining space proportionally among those children. Children without flex retain their natural size.

Equal distribution (1:1):

{
"type": "stack",
"direction": "row",
"gap": 8,
"children": [
{"type": "text", "text": "Left", "flex": 1},
{"type": "text", "text": "Right", "flex": 1}
]
}

Proportional layout (1:2):

{
"type": "stack",
"direction": "row",
"gap": 8,
"children": [
{"type": "text", "text": "Sidebar", "flex": 1},
{"type": "text", "text": "Content", "flex": 2}
]
}

Fixed + flexible mix:

{
"type": "stack",
"direction": "row",
"gap": 8,
"children": [
{"type": "image", "src": "sf-symbol:star.fill", "width": 20, "height": 20},
{"type": "text", "text": "Fills remaining space", "flex": 1}
]
}

Padding

16
[8, 12]
[8, 12, 8, 12]

A single number applies equally to all sides; arrays support the following formats:

ElementsFormatDescription
2[vertical, horizontal]Top/bottom and left/right equal spacing
4[top, right, bottom, left]CSS clockwise order

Full Example

Configuration File

scriptings:
- generic:
name: "server-status"
script_url: "https://example.com/scripts/server-status.js"
timeout: 20
env:
API_URL: "https://api.example.com/status"

widgets:
- name: "server-status"
env:
REGION: "Asia"

Widget Script

export default async function(ctx) {
const apiUrl = ctx.env.API_URL;
const region = ctx.env.REGION;

let result;
try {
const resp = await ctx.http.get(apiUrl + '?region=' + region);
result = await resp.json();
} catch (e) {
return {
type: 'widget',
padding: 16,
children: [{
type: 'text',
text: 'Failed to load',
textColor: '#FF3B30'
}]
};
}

// Adjust layout based on widget family
if (ctx.widgetFamily === 'accessoryRectangular') {
return {
type: 'widget',
children: [{
type: 'text',
text: result.name + ': ' + result.status,
font: { size: 'headline', weight: 'semibold' }
}]
};
}

return {
type: 'widget',
backgroundGradient: {
type: 'linear',
colors: ['#1a1a2e', '#16213e'],
startPoint: { x: 0, y: 0 },
endPoint: { x: 1, y: 1 }
},
padding: 16,
children: [
{
type: 'stack',
direction: 'row',
alignItems: 'center',
gap: 8,
children: [
{
type: 'image',
src: 'sf-symbol:server.rack',
color: '#007AFF',
width: 20,
height: 20
},
{
type: 'text',
text: result.name,
font: { size: 'headline', weight: 'bold' },
textColor: '#FFFFFF'
}
]
},
{ type: 'spacer' },
{
type: 'stack',
direction: 'column',
gap: 4,
children: [
{
type: 'text',
text: 'Region: ' + region,
font: { size: 'subheadline' },
textColor: { light: '#666666', dark: '#AAAAAA' }
},
{
type: 'text',
text: 'Status: ' + result.status,
font: { size: 'subheadline', weight: 'semibold' },
textColor: result.status === 'OK' ? '#34C759' : '#FF3B30'
}
]
},
{
type: 'date',
date: new Date().toISOString(),
format: 'relative',
font: { size: 'caption2' },
textColor: '#888888'
}
]
};
}

Widgets in Modules

Module files can also include a widgets field to define widgets. Widgets defined in a module become active when the module is enabled.

name: "Network Monitor Module"
description: "Display network status in widgets"
author: "module-author"

scriptings:
- generic:
name: "net-monitor"
script_url: "https://example.com/scripts/net-monitor.js"
timeout: 20

widgets:
- name: "net-monitor"

When referencing modules in the main configuration, you can pass environment variables to the module's widgets via env:

modules:
- url: "https://example.com/net-monitor.yaml"
enabled: true
env:
REFRESH_INTERVAL: "300"
ALERT_THRESHOLD: "90"