Writing the manifest
What goes in manifest.json: identity, API and app version floors, the entry document, sizing on the grid, and the schema line that gives you autocompletion.
manifest.json sits at the root of the widget folder and declares everything
the host needs to know before it runs a line of your code: who the widget is,
which API it speaks, what it may access, what the user can configure, and how
big it starts. Nothing is inferred; if it is not in the manifest, the widget
does not have it.
The starting point
Scaffolding a widget (or adding the dev kit to a folder) gives you this manifest:
{
"$schema": "./.deskdash/manifest.schema.json",
"id": "bus-times",
"name": "Bus Times",
"version": "0.1.0",
"apiVersion": 1,
"description": "One line saying what this widget shows or does",
"author": "",
"permissions": {},
"settings": [
{ "key": "title", "type": "text", "label": "Title", "default": "" },
"panelStyle"
],
"defaultSize": { "w": 4, "h": 2 },
"minSize": { "w": 2, "h": 2 }
}Every line of it earns its place, so the rest of this page walks through the fields in the order you will care about them. The exhaustive field tables live in the manifest reference.
Identity
id is the widget's stable identity: lowercase letters, digits, dots and
dashes, starting with a letter or digit, and it must equal the folder name.
The host treats a mismatch as an error, because the id doubles as the URL
path your files are served from.
While you develop, the id is simply yours to pick. When you publish, the
store assigns the public id itself: it becomes yourhandle.widget-name,
derived from the widget's name, and whatever id you wrote locally is
replaced. Details in the publishing guide.
name is the display name users see everywhere (and, on publish, the source
of that id slug). description is one plain sentence shown in listings.
author is informational locally; the store overwrites it with your
publisher handle.
The three versions
Three fields carry version meaning, and they gate different things:
versionis yours. The app treats it as an opaque label, but the marketplace requires dotted numbers (1.2.3style) and every update must carry a strictly higher one, so use orderable numbers from day one.apiVersionnames the bridge contract the widget was written against. It is1today and changes rarely; the host refuses manifests newer than itself and renders a needs-an-update tile for widgets older than its supported floor. The lifecycle is on errors and versioning.minAppVersion(optional) is a feature floor: "this widget uses a permission or capability first shipped in DeskDash x.y.z". Raise it when you adopt something newer than the oldest app you intend to support, for example bundled fonts need0.2.0. An older app then shows a clean "needs DeskDash x.y.z or newer" message instead of a confusing failure. The current floors are listed in the reference.
The entry document
entry names the HTML document the widget boots from. It defaults to
index.html, so most manifests omit it. If you set it, it must be a plain
relative path inside the widget folder: no leading slash, no .., no
backslashes. The same rules apply to popout.entry if the widget declares
a popout.
Sizing on the grid
Widgets live on a grid, and defaultSize and minSize are measured in grid
cells, not pixels: { "w": 4, "h": 2 } is four cells wide, two tall.
defaultSize is what a fresh instance gets; minSize is the smallest the
user can resize it to. Both accept 1 to 64 per axis.
How many pixels a cell is depends on the user's monitor and their grid
density setting, so never design for an exact pixel size. Design for the
range instead: make minSize the smallest shape the widget is genuinely
useful at, and test what it looks like both there and much larger.
Theming and tokens covers the autoscale helpers that
make readouts follow the widget's size.
The schema line
"$schema": "./.deskdash/manifest.schema.json"The dev kit generates a JSON Schema
describing the whole manifest format, and this line points your editor at it.
With it in place you get autocompletion for every field, inline validation
while you type, and hover documentation. The host ignores the field, so it is
safe to keep in published widgets even though the generated .deskdash/
folder itself does not ship.
Permissions and settings
The two biggest sections of a real manifest each have their own guide:
permissionsdeclares every capability the widget needs; everything is deny-by-default and users consent at install time. See the permission reference for the full list.settingsdeclares the fields users edit in the widget's settings dialog, including shared presets like"panelStyle". See settings and presets.
Strict on purpose
The manifest parser rejects unknown fields instead of skipping them. That
sounds harsh, but it means a typo like "defualtSize" fails loudly at scan
time with a message naming the field, rather than silently doing nothing and
leaving you staring at a widget that ignores its configured size.
Two real manifests
The Clock widget is about as small as a useful manifest gets. Note the
settings array mixing full field objects with the "panelStyle" preset
name:
{
"id": "clock",
"name": "Clock",
"version": "0.1.0",
"apiVersion": 1,
"description": "Time and date, driven by the host's tick source",
"author": "deskdash",
"permissions": { "time": true },
"settings": [
{ "key": "format24h", "type": "boolean", "label": "24-hour clock", "default": true },
{ "key": "showSeconds", "type": "boolean", "label": "Show seconds", "default": true },
{ "key": "showDate", "type": "boolean", "label": "Show date", "default": true },
"panelStyle"
],
"defaultSize": { "w": 6, "h": 3 },
"minSize": { "w": 3, "h": 2 }
}System Controls shows the two opt-ins Clock does not need: interactive
(the widget captures mouse input; see
interactivity) and popout (a second document
it may open; see popouts):
{
"id": "system-controls",
"name": "System Controls",
"version": "0.1.1",
"apiVersion": 1,
"description": "Wifi, volume and battery in one bar: network list with connect/disconnect, working volume slider, settings shortcuts",
"author": "deskdash",
"permissions": {
"system": true,
"systemControls": true
},
"interactive": true,
"popout": { "max": { "w": 4, "h": 4 }, "entry": "pane.html" },
"settings": [
{ "key": "showWifi", "type": "boolean", "label": "Show wifi", "default": true },
{ "key": "showVolume", "type": "boolean", "label": "Show volume", "default": true },
{ "key": "showBattery", "type": "boolean", "label": "Show battery", "default": true },
"panelStyle",
"accentColor"
],
"defaultSize": { "w": 4, "h": 1 }
}No minSize here means it falls back to the default minimum of one cell.