What a widget is
The mental model: a folder of plain HTML, CSS, and JavaScript in an isolated frame, a manifest that declares everything, and the dd SDK as the only door to the system.
A DeskDash widget is a plain web folder. No bundler, no framework, no build step, no dependencies to install:
my-widget/
├─ manifest.json # identity, permissions, settings, default size
├─ index.html # the entry document
├─ widget.js # plain JavaScript, classic or ES modules
└─ style.css # styled with --dd-* tokensThe folder name must equal the manifest's id, and
the manifest declares everything up front: what the
widget is, what it may access, and what users can configure. If you can
write a web page, you have all the skills already; the rest of these docs is
about what makes a widget different from a page.
The frame it runs in
Each widget instance runs in a locked-down sandboxed frame with an isolated origin. That single decision rules out a lot, on purpose:
- No network.
fetch, XHR and WebSockets are blocked; remote images do not load. - No browser storage: no
localStorage, cookies, or IndexedDB. - No reach into the app, other widgets, or the system.
Nothing your code can do escapes the frame. Every real-world capability comes back in through one door, gated by the manifest. The full containment story is on how the sandbox works.
The dd global: the single door
The host serves an SDK script that defines a global dd. It is the entire
system surface: time, settings, storage, HTTP, system vitals, media, and
everything else flows through it, and every call is checked against the
permissions your manifest declared and the user granted.
<script src="/__sdk/widget-sdk.js"></script>
<script src="widget.js"></script>await dd.ready; // nothing works until the host answers
dd.time.onTick(({ epochMs }) => { // needs "time" in the manifest
render(epochMs);
});The SDK also registers the dd-* components and
applies the user's theme to your document, which is why widgets follow
the design tokens for free.
Instances on a grid
Users do not "run" your widget; they place instances of it on a grid that spans their desktop. Sizes are measured in grid cells, your manifest declares the default and minimum, and users resize freely from there, including onto other monitors. The same widget can run as several instances at once, each with its own settings and its own storage.
Two consequences worth absorbing early:
- Design for a range of sizes, not a fixed one. A widget that only looks right at its default size is half finished.
- Instance state is per instance. Two clocks can show two time formats; two weather widgets, two cities.
Where widgets come from
Users install widgets from the built-in marketplace. Your own widgets live
as folders in the widgets directory (by default
Documents\DeskDash\widgets), which DeskDash scans at startup and on
reload; a folder there is a widget, immediately. Turning on
developer mode adds the tooling
around that loop, and when a widget is ready to share,
publishing takes it to the marketplace.
Ready to build one? Your first widget goes from empty folder to a working clock in a few minutes.
DeskDash widget docs
Build, style, and publish widgets for DeskDash with plain HTML, CSS, and JavaScript, no build step required.
Developer mode and the dev kit
Turn on developer mode to scaffold widgets, get typed autocomplete from the generated dev kit, reload from the tray, and inspect running widgets.