# Widgets (Win10+)

{% hint style="warning" %}
**Experimental Feature**: Windows Widgets for PWAs is currently an experimental feature primarily supported in Microsoft Edge on Windows 11+. The API and behavior may change.
{% endhint %}

Windows Widgets allow your PWA to provide mini-applications displayed on the Windows widgets dashboard. Users can interact with your app content without opening the full application.

## Overview

PWA Widgets use the [Adaptive Cards](https://adaptivecards.io/) template format to render content in the Windows widget panel. The bundle handles:

* **Manifest configuration**: Declaring widgets in the Web App Manifest
* **Service worker integration**: Automatic widget lifecycle management (install, update, uninstall)
* **Periodic updates**: Background data refresh via Periodic Sync

## Configuration

Widgets are configured in the manifest section:

{% code title="config/packages/pwa.yaml" lineNumbers="true" %}

```yaml
pwa:
    manifest:
        widgets:
            - name: "Weather Widget"
              short_name: "Weather"
              description: "Current weather conditions at a glance"
              tag: "weather"
              ms_ac_template: 'app_widget_weather_template'  # Symfony route name
              data: 'app_widget_weather_data'                 # Symfony route name
              type: "application/json"
              auth: false
              update: 3600          # Update every hour (in seconds)
              multiple: false       # Only one instance allowed
              screenshots:
                  - src: 'images/widget-weather.png'
                    label: 'Weather widget preview'
              icons:
                  - src: 'images/widget-weather-icon.svg'
```

{% endcode %}

## Configuration Reference

| Property         | Type      | Required | Description                                             |
| ---------------- | --------- | -------- | ------------------------------------------------------- |
| `name`           | string    | Yes      | Widget title displayed to users                         |
| `description`    | string    | Yes      | Description of the widget                               |
| `tag`            | string    | Yes      | Unique identifier for the widget                        |
| `ms_ac_template` | URL/route | Yes      | URL or route name returning the Adaptive Cards template |
| `data`           | URL/route | Yes      | URL or route name returning widget data (JSON)          |
| `screenshots`    | array     | Yes      | At least one screenshot showing the widget              |
| `short_name`     | string    | No       | Shorter version of the widget name                      |
| `type`           | string    | No       | MIME type for widget data (default: `application/json`) |
| `auth`           | boolean   | No       | Whether the widget requires authentication              |
| `update`         | integer   | No       | Update frequency in seconds                             |
| `multiple`       | boolean   | No       | Allow multiple widget instances (default: `true`)       |
| `icons`          | array     | No       | Widget-specific icons (falls back to manifest icons)    |

## Server-Side Implementation

### Adaptive Cards Template

Create a controller that returns an Adaptive Cards template:

{% code title="src/Controller/WidgetController.php" lineNumbers="true" %}

```php
<?php

declare(strict_types=1);

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Attribute\Route;

final class WidgetController extends AbstractController
{
    #[Route('/widget/weather/template', name: 'app_widget_weather_template')]
    public function template(): JsonResponse
    {
        return $this->json([
            'type' => 'AdaptiveCard',
            '$schema' => 'http://adaptivecards.io/schemas/adaptive-card.json',
            'version' => '1.5',
            'body' => [
                [
                    'type' => 'TextBlock',
                    'text' => '${city}',
                    'size' => 'Large',
                    'weight' => 'Bolder',
                ],
                [
                    'type' => 'TextBlock',
                    'text' => '${temperature}°C - ${condition}',
                    'size' => 'Medium',
                ],
            ],
        ]);
    }

    #[Route('/widget/weather/data', name: 'app_widget_weather_data')]
    public function data(): JsonResponse
    {
        // Fetch actual weather data from your service
        return $this->json([
            'city' => 'Paris',
            'temperature' => 22,
            'condition' => 'Sunny',
        ]);
    }
}
```

{% endcode %}

## How the Service Worker Works

The bundle automatically generates service worker code that:

1. **On widget install** (`widgetinstall` event):
   * Fetches the Adaptive Cards template from `ms_ac_template`
   * Fetches data from the `data` URL
   * Renders the widget using `self.widgets.updateByTag()`
   * Registers periodic sync if `update` is configured
2. **On periodic sync** (`periodicsync` event):
   * Refreshes the template and data
   * Updates the widget with fresh content
3. **On widget uninstall** (`widgetuninstall` event):
   * Unregisters periodic sync when the last widget instance is removed
4. **On service worker activation**:
   * Updates all registered widgets with fresh data

## Multiple Widgets

You can configure multiple widgets:

{% code title="config/packages/pwa.yaml" lineNumbers="true" %}

```yaml
pwa:
    manifest:
        widgets:
            - name: "Weather Widget"
              tag: "weather"
              ms_ac_template: 'app_widget_weather_template'
              data: 'app_widget_weather_data'
              update: 3600
              screenshots:
                  - src: 'images/widget-weather.png'
                    label: 'Weather'

            - name: "News Headlines"
              tag: "news"
              ms_ac_template: 'app_widget_news_template'
              data: 'app_widget_news_data'
              update: 1800   # Every 30 minutes
              multiple: true
              screenshots:
                  - src: 'images/widget-news.png'
                    label: 'News headlines'
```

{% endcode %}

## Requirements and Limitations

* **Platform**: Microsoft Edge on Windows 11+ only
* **Template format**: Must use [Adaptive Cards](https://adaptivecards.io/) JSON format
* **Data format**: Widget data endpoints must return valid JSON
* **URLs**: Template and data URLs must be within the service worker scope
* **Update intervals**: Subject to browser/OS scheduling policies (minimum interval may be enforced)
* **Icon size**: Icons larger than 1024x1024 are ignored

## Resources

* [Microsoft PWA Widgets Documentation](https://learn.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/how-to/widgets)
* [Adaptive Cards Designer](https://adaptivecards.io/designer/)
* [Adaptive Cards Schema](https://adaptivecards.io/explorer/)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://pwa.spomky-labs.com/experimental-features/widgets-win10+.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
