# widgets manifest member

> The widgets array registers Adaptive Cards widgets for the Windows 11 Widgets Board, rendered and refreshed by the PWA's service worker on widgetinstall.

`widgets` is an array of widget definitions that an installed PWA offers to the operating
system's widget surface. Each definition names an Adaptive Cards template and a JSON data URL;
the browser draws the card, and the app's service worker fills and refreshes it in response to
widget lifecycle events, with no page open.

Microsoft Edge 108 and later on Windows 11 is the only implementation, and it targets the
Windows 11 Widgets Board (Microsoft Edge documentation, "Build PWA-driven widgets"). The
member is a Microsoft explainer, not a W3C or WICG draft; Chrome 155, Firefox 157, and Safari
26 drop it during parsing.

## Member

- **Type**: array of widget-definition objects. Required keys: `name`, `description`, `tag`
  (the string the service worker uses to address the widget), `ms_ac_template` (URL of the
  Adaptive Cards template), and `data` (URL of the JSON the template is bound to). Optional
  keys: `short_name`, `template` (informational only in Edge), `type` (MIME type of the data,
  default `application/json`), `icons`, `screenshots`, `backgrounds`, `auth` (boolean), and
  `update` (refresh period in seconds).
- **Default**: absent. Without the member the app offers nothing on the Widgets Board; an
  entry missing `tag` or `ms_ac_template` is not offered.
- **Example value**: `[{ "name": "Open tasks", "tag": "tasks", "ms_ac_template": "/widgets/tasks.json", "data": "/widgets/tasks-data.json" }]`.

Installing the app only lists its widgets in the board's **Add widgets** picker. A widget
becomes active when the user adds it, which fires `widgetinstall` in the service worker; the
worker then calls `self.widgets.updateByTag(tag, { template, data })` to render it. Further
events are `widgetuninstall`, `widgetresume` (the board became visible again), and
`widgetclick` (an Adaptive Cards action the user triggered, with the action verb on
`event.action`). Edge also calls `self.widgets.getByTag()`, `getByInstanceId()`, and
`matchAll()` to enumerate what is installed.

:::observed
Chrome 155 on Windows 11 (English UI), DevTools > Application > Manifest: a manifest with a
`widgets` array shows no widgets section and no **Errors and warnings** entry, the member is
dropped without a message. Edge 154 on the same machine adds the widget to the Widgets Board
picker under the app's `name` after installation, and `'widgets' in self` evaluates to `true`
in the app's service worker console only in Edge.
:::

## Examples

The examples describe one task-list widget on an app installed from `https://tasks.example/`.

### Declaring a widget with its template, data, and refresh period

The `tag` is what every service-worker call keys on, so it should be stable across releases.
`update: 900` asks Edge to refetch `data` every fifteen minutes while the widget is on the
board.

```json
{
  "widgets": [
    {
      "name": "Open tasks",
      "short_name": "Tasks",
      "description": "Your open tasks, at a glance",
      "tag": "open-tasks",
      "template": "open-tasks",
      "ms_ac_template": "/widgets/open-tasks.ac.json",
      "data": "/widgets/open-tasks-data.json",
      "type": "application/json",
      "update": 900,
      "icons": [{ "src": "/widgets/icon-96.png", "sizes": "96x96" }],
      "screenshots": [
        { "src": "/widgets/open-tasks-wide.png", "sizes": "600x400", "label": "Open tasks widget listing three tasks" }
      ]
    }
  ]
}
```

The `screenshots` entry is shown in the picker, so it should depict the rendered card rather
than the app.

### Rendering on install and refreshing on resume

The service worker fetches the template and data named in the widget's definition and hands
both to `updateByTag()`. The same function runs for `widgetresume`, which is the hook for
data that has gone stale while the board was hidden.

```js
async function renderWidget(widget) {
  const definition = widget.definition;
  const template = await (await fetch(definition.msAcTemplate)).text();
  const data = await (await fetch(definition.data)).text();
  await self.widgets.updateByTag(definition.tag, { template, data });
}

self.addEventListener('widgetinstall', (event) => {
  event.waitUntil(renderWidget(event.widget));
});

self.addEventListener('widgetresume', (event) => {
  event.waitUntil(renderWidget(event.widget));
});
```

Edge exposes the definition on `event.widget.definition` with the manifest keys converted to
camelCase, which is why the template URL is read as `msAcTemplate`.

### Detecting the API and handling a card action

`self.widgets` exists only where widgets are implemented, so a service worker shared across
browsers guards every call. The `widgetclick` handler receives the action verb declared in
the Adaptive Cards template and can update the card in place.

```js
if ('widgets' in self) {
  self.addEventListener('widgetclick', (event) => {
    if (event.action !== 'complete-task') return;
    event.waitUntil(
      fetch('/api/tasks/complete', { method: 'POST', body: JSON.stringify(event.data) })
        .then(() => renderWidget(event.widget)),
    );
  });
} else {
  // No widget surface in this browser; the app keeps its in-page task list only.
}
```

Outside Edge the `else` branch is the whole story: the manifest entry is inert and the worker
registers no listeners.

## See also

- [PWAs on Microsoft Edge (sidebar, store)](/reference/platforms/edge/)
- [PWAs on Windows](/reference/platforms/windows/)
- [icons manifest member](/reference/manifest/icons/)
- [screenshots manifest member](/reference/manifest/screenshots/)
- [Build PWA-driven widgets](https://learn.microsoft.com/en-us/microsoft-edge/progressive-web-apps/how-to/widgets) (learn.microsoft.com)
- [PWA-driven Widgets explainer](https://microsoftedge.github.io/MSEdgeExplainers/PWAWidgets/) (microsoftedge.github.io)