# Widgets déclaratifs

> Des widgets d'accueil sans page ni code : un template, des champs de config saisis par l'utilisateur, une source de données allowlistée — la plateforme collecte et rend à la charte Capibara.
> Catégorie : Référence · mis à jour le 2026-09-04 · plateforme v1

## Le principe

Un widget **déclaratif** est la façon la plus légère d'apparaître sur
l'accueil d'un tenant : vous ne livrez **ni page, ni code**. Vous décrivez le
widget dans le manifeste — un `template` fourni par Capibara, d'éventuels
champs `config` que l'utilisateur du tenant remplit (ex. une adresse), une
`source` de données — et la plateforme fait tout le reste :

1. elle **collecte** la donnée côté serveur (fetch borné, HTTPS, host
   allowlisté par vos capabilities `http.fetch:<host>`) ;
2. elle **rend** le widget avec ses propres composants, à la charte graphique
   Capibara — jamais d'iframe, jamais de site externe ;
3. elle **stocke** la configuration saisie par l'utilisateur sur son
   installation. Votre code n'y touche jamais (et n'existe d'ailleurs pas,
   pour un widget purement déclaratif).

C'est le même esprit qu'un bot Discord : vous déclarez, la plateforme exécute.

## Déclaration dans le manifeste

```json
{
  "capabilities": [
    "ui.widget",
    "http.fetch:geocoding-api.open-meteo.com",
    "http.fetch:api.open-meteo.com"
  ],
  "contributes": {
    "widgets": [
      {
        "key": "meteo",
        "title": "Météo",
        "kind": "declarative",
        "template": "weather",
        "config": [
          { "key": "address", "label": "Votre ville ou adresse", "type": "text", "placeholder": "Paris", "required": true }
        ],
        "minHeight": 220
      }
    ]
  }
}
```

| Champ | Type | Règle |
|---|---|---|
| `kind` | `"declarative"` | obligatoire — distingue le widget déclaratif d'un widget `embedUrl`. |
| `template` | string | `weather`, `kpi` ou `list` (catalogue plateforme, il s'étoffera). |
| `config` | tableau | optionnel, max 6 champs — `{ key, label (≤ 60), type: "text"\|"number", placeholder?, required? }`. Saisis par l'utilisateur SUR le widget, stockés par la plateforme. |
| `source` | objet | optionnel — `{ url, map? }` : URL HTTPS templatée avec les champs de config (`…?q={address}`) + mapping `champ de sortie → chemin dans la réponse JSON` (`"value": "data.count"`). |
| `minHeight` | number | optionnel, 120-1200 px. |

**Règle d'allowlist (bloquante à la validation)** : tout host appelé — celui
de `source.url`, ou les hosts intégrés du template — doit être déclaré en
capability `http.fetch:<host>`. Le validateur du manifeste vous liste les
capabilities manquantes.

## Les templates

### `weather` — météo (source intégrée)

Aucune `source` à fournir : le template embarque Open-Meteo (géocodage de
l'adresse saisie puis conditions actuelles — température, ressenti, vent,
humidité, ciel, heure locale). Déclarez les deux hosts :
`http.fetch:geocoding-api.open-meteo.com` et `http.fetch:api.open-meteo.com`.
Champ de config attendu : `address` (requis).

### `kpi` — un chiffre clé

Sans `source` : rend les valeurs de config `value` et `label` telles quelles
(mode statique). Avec `source` : la réponse JSON est mappée via `map`
(ex. `{ "value": "stats.total" }`) — chemins pointés, index de tableau
autorisés (`results.0.name`).

### `list` — une liste d'éléments

La `source` doit produire un champ `items` (via `map`, ex.
`{ "items": "data.entries" }`) : tableau d'objets `{ title | name | label,
subtitle? | description? }` — 6 éléments affichés au maximum.

## Ce que voit l'utilisateur

- Il ajoute votre widget depuis « Personnaliser » › « Ajouter un widget » sur
  son accueil (rubrique **Apps** du sélecteur — le widget porte le nom de votre
  app).
- Si un champ `required` n'est pas rempli, le widget affiche directement le
  petit formulaire de configuration ; ensuite, un bouton « Modifier » discret
  permet de changer la saisie (ex. changer de ville).
- La donnée est rafraîchie à l'affichage (avec un cache client de quelques
  minutes) — prévoyez une `source` qui supporte des lectures régulières.

## Bornes d'exécution

Le fetch plateforme applique les mêmes bornes que la sandbox : HTTPS
obligatoire, host allowlisté, **redirections refusées**, timeout 10 s,
réponse ≤ 512 Ko, JSON uniquement. Une source injoignable produit un message
d'erreur sobre dans le widget — jamais de widget cassé.

## Exemple complet

Le tutoriel [Démarrer](/dev/docs/demarrer) construit pas à pas un widget
météo déclaratif (manifeste seul, sans code), l'installe en test puis le
publie. L'app « Météo (exemple) », téléchargeable depuis l'[index de la
documentation](/dev/docs), montre ensuite la version avec code hébergé (page
et widget rendus par le Kit).
