Build a custom Stackyard widget
A widget is one folder in ui/widgets/. This page builds one from the template in the repository.
A widget has three files. widget.json defines its settings. data.js runs on the server and calls your service. index.html runs on the dashboard and draws the result.
1. Copy the template
Section titled “1. Copy the template”cp -r docs/widget-template ui/widgets/mywidget2. Settings
Section titled “2. Settings”{ "name": "mywidget", "label": "My Widget", "sizes": ["small", "medium"], "fields": [ { "key": "url", "type": "text", "label": "Service URL", "placeholder": "http://host:port" }, { "key": "apiKey", "type": "secret", "label": "API key", "optional": true }, { "key": "showTotal", "type": "toggle", "label": "Show total", "default": true } ]}name must match the folder. Each field becomes a row in the widget’s settings. A secret never returns to the browser. See Manifest.
3. Data
Section titled “3. Data”module.exports = async function (ctx) { const { url, apiKey } = ctx.config; if (!url) ctx.fail('Enter the service URL.', { kind: ctx.KIND.INVALID });
const r = await ctx.fetchJSON(`${ctx.normalizeBase(url)}/api/items`, { headers: apiKey ? { 'X-Api-Key': apiKey } : {}, timeout: 8000, });
return { items: (r.data.items || []).slice(0, 10).map(i => ({ name: i.name })), total: r.data.total ?? 0, };};The return value is served at /api/widget-data/<id>. The template returns { error } when the URL is missing. Use ctx.fail as shown, so the widget shows its failure state. See Data.
4. Page
Section titled “4. Page”<script type="module"> import { poll } from '/js/widget-toolbox.js?v=1'; const root = document.getElementById('root');
poll({ render: data => { root.textContent = `${data.total} items`; }, isEmpty: data => !data.items?.length, interval: 30000, });</script>poll() fetches the data and handles loading, empty, stale and failed states. The template adds the markup and styles. See Widget page.
5. Try it
Section titled “5. Try it”Restart Stackyard, then in Settings, Dashboard, press Add and pick My Widget. If it is missing, the container log says why.
Before a pull request, go through the checklist.