# Widgets in the Total.js CMS: use them in a page and write your own

> How a widget appears in the HTML of a page (the data-cms attribute and its JSON), the parts of a widget file, the CLASS placeholder, rendering a widget on the server with exports.render and installing widgets through the API.

Framework: cms
Product: CMS (cms@8071e48)
Language: en
Content-SHA256: 7c7f694f4ddf21bd01573bc29d3f7c18c074fe27d66d1f6103dbd3de11083bdb
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: 
Review: not-recorded

A **widget** is a block that you place in a page: a headline, an alert, a gallery. It carries its own style, a form to configure it in the editor and, optionally, code that renders it on the server. A widget is one HTML file, like a component of [Flow](/en/flow/write-a-component/), and the CMS stores it in its metadata.

## A widget inside a page

In the HTML of a page, a widget is a `div` with two attributes:

```html
<div data-cms="headline__%7B%22h%22%3A%22h1%22%2C%22align%22%3A%22left%22%7D" data-cms-id="h1">
	<h1 class="w-headline-h">Hello CMS</h1>
	<p>Some text</p>
</div>
```

- `data-cms` is `<widget id>__<configuration>`, where the configuration is a JSON object written with `encodeURIComponent`. The editor writes it; you can write it yourself when you generate pages.
- `data-cms-id` is the identifier of the instance in the page.

When the page is served, the CMS removes the `data-cms` attribute, keeps the HTML that is inside, and adds the style of every widget of the page to the head. If the widget is not installed, its block is dropped.

## The parts of a widget file

| Part | What it is for |
|---|---|
| `<script total>` | the metadata and the server code: `exports.id`, `name`, `author`, `version`, `preview` (an image, or a data URI), `config` (the defaults), and optionally `dependencies`, `install`, `uninstall` and `render` |
| `<style>` | the CSS of the widget |
| `<body>` | the design of the widget as the editor shows it; elements with the class `CMS_edit` are the editable ones; the other `CMS_*` classes (`CMS_repeat`, `CMS_remove`, `CMS_unwrap`...) are markers for the editor, and the compiler strips them before the page is served |
| `<settings>` | the form that edits `config` in the editor (jComponent inputs whose path starts with `?.`) and a `<script>` with `exports.save(config, el)` that changes the design when the configuration changes |
| `<template>` | an optional template for the widget |
| `<readme>` | the help of the widget |

`CLASS` in the style, the settings, the template and the design is replaced by a class that belongs to the widget (`w-` followed by its id), so two widgets never share a rule: in the widget `alert`, `.CLASS-color1` becomes `.w-alert-color1`.

`exports.dependencies` accepts a list or a string separated with commas: an address ending in `.js` becomes a `<script src>` and one ending in `.css` a `<link rel="stylesheet">`, added to the head of the page.

## Render on the server

A widget without `exports.render` is only cleaned and served as it is. With `render` it can build its HTML from the configuration:

```html
<script total>

	exports.id = 'hello';
	exports.name = 'Hello';
	exports.author = 'Me';
	exports.version = '1';
	exports.config = { text: 'world' };

	exports.render = function(opt, next) {
		next('<p class="w-hello">Hello ' + (opt.config.text || '').toUpperCase() + '</p>', true);
	};

</script>

<style>
	.CLASS { color: #07c; }
</style>

<body>
	<p class="CLASS CMS_edit">Hello world</p>
</body>
```

`opt.config` is the configuration of the instance, `opt.html` the HTML that was inside the block, and `opt.id`, `opt.uid` and `opt.body` describe it. `next(html, replace)` gives the HTML to serve; with `true` as the second argument it replaces the whole block. We saved this file in a local CMS and a page with `data-cms="hello__..."` and `{"text":"mundo"}` came out as `<p class="w-hello">Hello MUNDO</p>`, with `.w-hello{color:#07c}` in the head. The official widget `picture` uses the same function to add `loading="lazy"` to its image, and `code` to print the code of its settings.

`exports.install` and `exports.uninstall` run with the database of the CMS when the widget is added, changed or removed.

## Install and remove widgets

The plugin *Widgets* of the admin imports a file; through the API it is `widgets_save` with `{ "html": "<file content>", "singleton": true }` (`singleton` skips the widget when it already exists), `widgets_list`, `widgets_read`, `widgets_detail` and `widgets_remove`. They need the permission `widgets` (see [the admin API](/en/cms/the-admin-api/)). The 43 official widgets are in [the widgets repository](/en/cms/the-widgets-repository/).
