An EdgeOS widget is a small web page. You write plain HTML, CSS and JavaScript, describe the widget in a widget.json, and EdgeOS puts it on the XENEON EDGE next to the built-in widgets, with the same options panel, looks and text sizes. Your own widgets are free to build and import.
What a widget is
A folder, or a zip of one, with two files:
my-widget/
├── widget.json name, size, options
└── index.html the widget, plain HTML/CSS/JS
Add any other files the page needs (scripts, styles, images) next to them. Relative paths to them work.
Import it
Add the widget
Either open the Widgets page in EdgeOS and choose Import widget…, or drop the folder into %LOCALAPPDATA%\EdgeOS\widgets\.
Place it
The widget appears under Imported on the Widgets page and in the layout picker. Add it to any profile and it shows in Desktop Mode, in the iCUE widget and in the app's preview.
widget.json
{
"id": "hello-widget", // folder name after import; letters, digits, - _ .
"name": "Hello Widget",
"description": "One line for the catalogue card.",
"author": "You",
"version": "1.0.0",
"entry": "index.html", // optional, default index.html
"w": 3, "h": 1, // default size in grid units (desktop grid is 12 × 4)
"options": [ // optional; shown on the Widgets page and per placement
{ "key": "greeting", "label": "Greeting", "type": "text", "default": "Hello, Edge" },
{ "key": "showCpu", "label": "Show CPU", "type": "switch", "default": true },
{ "key": "unit", "label": "Unit", "type": "seg", "default": "c", "values": [["c", "°C"], ["f", "°F"]] }
]
}
idbecomes the folder name after import, and it's what keeps your widget's storage across updates. Use letters, digits,-,_and..wandhare the default size in grid units. The desktop grid is 12 × 4.optionsshow on the Widgets page and on each placement.textis a text box,switchan on/off toggle andsega segmented choice fromvalues, each a[value, label]pair.
index.html
EdgeOS loads your page in a sandboxed iframe that fills the tile, with allow-scripts allow-same-origin allow-forms allow-popups.
Each widget is served from an origin of its own:
http://w-<hash>.localhost:57140/custom/<id>/
The hash comes from the widget's id, so it stays the same when you update the widget and your localStorage is kept.
What your page receives
| When | How | Payload |
|---|---|---|
| On load | Query string | ?mode=desktop or ?mode=widget, plus &options= and the options as JSON |
| On load, and when options change | postMessage | { type: "edgeos-options", options, mode } |
| Every second while visible | postMessage | { type: "edgeos-state", state } |
state is the same object the built-in widgets use:
{
"edge": { "found": true, "mode": "desktop", "bounds": { "x": 1920, "y": 0, "w": 2560, "h": 720 }, "icue": true },
"system": { "cpu": 12, "gpu": 4, "gpuAvailable": true, "ramUsed": 11.2, "ramTotal": 31.1, "ramPct": 36 },
"media": { "title": "…", "artist": "…", "album": "…", "status": "playing|paused|stopped|none", "position": 42, "duration": 213, "thumbKey": "…" }
}
A minimal listener:
window.addEventListener("message", e => {
const m = e.data || {};
if (m.type === "edgeos-options") applyOptions(m.options);
if (m.type === "edgeos-state") draw(m.state);
});
Design notes
Background
Make the body background transparent so the dashboard's tile colour and corner radius show through, or paint your own.
Text size
EdgeOS sets the font-size of your page's <html> element to the user's text size (Appearance → Text size × the widget's own Text size under Widgets → Customize) and mirrors it as --scale on the same element. Size your text in em or rem and it follows both sliders. Fixed px sizes ignore them.
Touch
The Edge is a touchscreen. Keep tap targets 44 px or larger, avoid controls that only appear on hover, and don't expect a keyboard.
Sizes
The same widget can be 1 × 1 in Widget Mode and 4 × 2 on the desktop. Use container-relative units (cqmin, percentages) rather than fixed pixels.
Network and the OS
Network access is up to your page: EdgeOS doesn't proxy requests. Anything that needs the operating system, such as launching apps or reading files, belongs in a helper process, the way Launchify and Deckord do it.
iCUE widgets in EdgeOS
Any .icuewidget imports the same way. EdgeOS unpacks it and serves its index.html with a script at the top of <head> that provides what iCUE itself does:
window.iCUE = { isPreview: false };- one global
letperx-icue-propertymeta tag, holding the value set in EdgeOS, or itsdata-default; let icueEvents.icueEvents.onICUEInitialized()runs once the page has loaded andicueEvents.onDataUpdated()whenever a value changes. Changes apply live: changing a setting in EdgeOS never reloads the widget.
Every property shows in Customize → Options, in the widget's own x-icue-groups panels, with slider units from data-unit-label.
- Screen colours. The four names iCUE reserves for the screen's colours (
accentColor,backgroundColor,textColorandtransparency) are set under Appearance instead, as the tile's look: its accent, text colour and background. A tile with a background of its own makes the widget see-through over it (transparency90). - Text size. Appearance → Text size, times the global Text size, multiplies the widget's own
textScaleslider, or one named…TextScale. A widget without one is zoomed. - Following colours. A widget with a
followIcueColorsswitch has it turned on while the tile sets a colour. - Links. The link provider (
widgetbuilder.linkprovider) is shimmed:window.plugins.Linkprovider.open(url)has EdgeOS open an http(s) link in the default browser. Otherrequired_pluginsdon't have a shim yet, and the widget will report that feature as missing.
The widget catalogue
EdgeOS can install widgets from a catalogue that QAEM publishes as a JSON file:
{
"widgets": [
{ "id": "hello-widget", "name": "Hello Widget", "description": "…", "author": "QaemDev", "version": "1.0.0",
"kind": "custom", // or "icue"
"download": "https://…/hello-widget.zip",
"homepage": "https://…" }
]
}
Installing downloads the zip over https and imports it. Installing from the catalogue is an EdgeOS Pro feature; importing your own files is free. The catalogue page is on its way, so for now the Widgets page has only Import widget….