How a widget works

How a widget works

Every tile on a dashboard is drawn by a widget. The built-in widgets and the ones you make are built the same way, from the same parts, so anything a built-in widget does, yours can do too.

If you know a little HTML and CSS you already know most of what you need. The rest is a small template language for putting your Homey’s values into the page. If you would rather not write it yourself, your AI assistant can build widgets for you.

The three parts

A widget is made of three things:

  • A manifest says what the widget is: its name, which devices it fits, how big a tile can be and which settings each tile can change.
  • A template says what the widget shows. It is HTML with Liquid in it, which fills in values such as the device’s name or the temperature.
  • A style says how it looks. It is plain CSS.

Here is a template and a style that show a room’s temperature:

<p class="name">{{ device.name }}</p><p class="big">{{ cap.measure_temperature.value | temp: 1 }}</p>
.name {  font: 500 13px var(--hd-font-ui);  color: var(--hd-text-muted);}.big {  font: var(--hd-number-weight) 48px var(--hd-font-display);}

device.name is the name of the tile’s device in Homey. cap.measure_temperature.value is its temperature, and temp: 1 writes it with one decimal and a degree sign. The style reads the theme’s fonts and colours through --hd-* variables, so the widget looks right in every theme.

You don’t write the manifest by hand in the app. When you make a widget, the editor builds it for you: the name you give it, the settings you add on the Settings tab, and the devices and tile sizes of the widget you started from. The manifest reference lists every field if you want to know what is behind it.

How a widget is drawn

When a tile needs drawing, Tiledash does four things:

  1. It collects what the widget can read: the tile’s device and its readings, what the tile’s settings are set to, the time and so on. The context reference lists all of it.
  2. It runs your template through Liquid with that data. Every value that Liquid writes out is escaped, so a device called <b>Lamp</b> shows exactly that.
  3. It cleans the result with DOMPurify against a fixed list of elements and attributes. Anything else is removed.
  4. It puts what is left into the tile’s own Shadow DOM, next to your style.

When something changes, a reading from Homey, a setting, or something the widget keeps in its own state, steps 2 to 4 run again. The new HTML is merged into the elements that are already there instead of replacing them. That is why a bulb keeps fading, a chart keeps its line and a focused button keeps its focus while the values underneath it move.

A widget that reads the clock (now, since(), until() or isToday()) is drawn again every minute. One that doesn’t holds no timer at all.

The hd-* elements, such as hd-bulb, hd-slider and hd-sparkline, do the moving parts. You write them in the template like any HTML element, and they animate, draw charts and send changes back to Homey on their own. The components reference lists them all with their attributes.

What a widget can and can’t do

A widget is code from someone who isn’t Tiledash, even when that someone is you. So it is held to a short list of rules, checked every time you save:

  • Output is escaped. Anything Liquid writes into the page is turned into plain text first. The raw filter exists in Liquid, but here it can’t undo that.
  • Only listed HTML. Templates can use a fixed set of HTML elements and the hd-* components. There are no scripts, links, <img> elements, forms or <style> elements, and id isn’t an allowed attribute. See the HTML reference. An inline style attribute can only set custom properties, such as style="--fill: 62%".
  • No JavaScript. When something is tapped, a short line in a small expression language runs. It is read by a parser and carried out by Tiledash, never handed to JavaScript, and it can only call a fixed list of actions.
  • Actions are checked. Before anything reaches your Homey, Tiledash checks that the device is on this Homey, that the reading can be changed and that the value fits. A refused action changes nothing and says why in a message.
  • CSS can’t load anything. url(), @import and @font-face aren’t allowed, so a style can’t fetch an image or a font from elsewhere.
  • Limits. A template or a style can be 20,000 characters long. A template may take 50,000 steps of work to draw (every tag, value and loop round counts, partials included), and a widget can render at most three levels of partials.
  • Only its own data. A template reads the data it is given and nothing else. It can’t reach the rest of the page or other tiles, and it can’t run code that fetches things. Pictures and video come in through the hd-image and hd-camera components, which fetch them without cookies or a referrer.

When you save, the editor draws your widget with demo devices in several states, including a device that is unavailable and settings left empty, and refuses a save that fails. Write the template so that it copes with a reading that is missing.

Your own widgets are a Pro feature

Changing how a built-in widget looks is free. The Style panel on any tile, with saved presets and CSS for a single tile, is open to everyone.

Where to start in the app

There are three ways in, and all of them open the same editor:

  • Your widgets in the sidebar lists everything you have made. New widget starts one, and New partial starts a piece of template that several widgets can share, with parameters of its own. Partials you installed from the store are listed there too, and the filter at the top shows only widgets or only partials.
  • Make a widget… at the bottom of the widget picker does the same while you are adding a tile.
  • Make this widget yours… in a tile’s menu in edit mode opens the editor with a copy of what that tile draws. The first time you save, the new widget is put on that tile.

New widget asks you to either Start empty or Start from a widget. Starting from a widget copies a built-in (or one of yours): its devices, its settings, its template and its style. That is the easiest way to learn, because you start from something that already works. Starting empty gives you a nearly blank widget with no device of its own, for things you build entirely from settings.

The editor has a Template tab and a Style tab, and a Settings tab for what each tile can choose. Panels beside the code list the data you can read (Data), the actions you can run (Actions), the components and partials (Catalog) and the expression language (Syntax). A preview on the right draws your widget with demo devices or with your own, as you type. Save (or ⌘S, Ctrl+S on Windows and Linux) makes it live on every tile that uses it, and the last 10 saves are kept to go back to.

Ready to build one? The next page makes a lamp tile from scratch.

Where to go next