Widgets
The widget system lets external modules add custom UI elements to Calendaria applications.
Overview
Section titled “Overview”Module developers can:
- Add custom buttons to the HUD, BigCal, and MiniCal
- Add custom indicator displays
- Replace built-in indicators with custom implementations
Widget points
Section titled “Widget points”Widgets can be inserted at these locations:
| Point | Location | Widget Types |
|---|---|---|
hud.buttons.left | Left side of HUD bar | Buttons |
hud.buttons.right | Right side of HUD bar | Buttons |
hud.indicators | Indicator section of HUD bar | Indicators |
hud.tray | Time controls tray | Buttons |
minical.sidebar | MiniCal sidebar | Buttons |
bigcal.actions | BigCal action bar | Buttons |
Access these via CALENDARIA.api.widgetPoints.
Replaceable elements
Section titled “Replaceable elements”Built-in indicator elements that custom widgets can replace. Replacements apply across all three applications (HUD, MiniCal, BigCal):
| Element ID | Description |
|---|---|
weather-indicator | Weather condition display |
season-indicator | Current season display |
era-indicator | Era/year display |
cycle-indicator | Cycle (zodiac, etc.) display |
Access these via CALENDARIA.api.replaceableElements.
Registering a widget
Section titled “Registering a widget”Basic button widget
Section titled “Basic button widget”Widgets registered during calendaria.ready appear on the first render of all Calendaria applications.
Hooks.once('calendaria.ready', () => { CALENDARIA.api.registerWidget('my-module', { id: 'my-button', type: 'button', insertAt: 'hud.buttons.right', icon: 'fas fa-star', label: 'My Button', tooltip: 'Click to do something', onClick: () => { console.log('Button clicked!'); } });});Indicator widget
Section titled “Indicator widget”An indicator renders from its icon, label, color, and tooltip properties:
CALENDARIA.api.registerWidget('my-module', { id: 'mana-indicator', type: 'indicator', insertAt: 'hud.indicators', icon: 'fas fa-gem', label: 'Mana: 50', color: '#3aa0ff', tooltip: 'Current mana', onAttach: (element) => { // Called when the widget is added to the DOM }});Custom widget
Section titled “Custom widget”A type: 'custom' widget supplies a render function. The function receives the location string ('hud', 'minical', or 'bigcal') and returns an HTML string, which Calendaria wraps in a <div class="calendaria-widget-custom">:
CALENDARIA.api.registerWidget('my-module', { id: 'mana-display', type: 'custom', insertAt: 'hud.indicators', render: (location) => { return ` <span class="indicator-icon"><i class="fas fa-gem"></i></span> <span class="indicator-label">Mana: 50</span> `; }, onAttach: (element) => { // Called when the widget is added to the DOM }});Replacement widget
Section titled “Replacement widget”A replacement that needs a render function must use type: 'custom'. The render function receives the location string and returns an HTML string:
CALENDARIA.api.registerWidget('my-module', { id: 'custom-weather', type: 'custom', replaces: 'weather-indicator', render: (location) => { const weather = CALENDARIA.api.getCurrentWeather(); return `<span>Custom: ${weather?.label || 'None'}</span>`; }});Widget configuration
Section titled “Widget configuration”Required properties
Section titled “Required properties”| Property | Type | Description |
|---|---|---|
id | string | Unique widget identifier within your module |
type | string | 'button', 'indicator', or 'custom' |
Insertion properties
Section titled “Insertion properties”One of these is required:
| Property | Type | Description |
|---|---|---|
insertAt | string | Widget point ID from widgetPoints |
replaces | string | Element ID from replaceableElements |
Button properties
Section titled “Button properties”| Property | Type | Description |
|---|---|---|
icon | string | FontAwesome icon class |
label | string | Button text (optional) |
tooltip | string | Hover tooltip text |
color | string | Icon color (CSS color value) |
onClick | function | Click handler |
disabled | boolean | When true on a replaces widget, hides the replaced built-in element |
Indicator properties
Section titled “Indicator properties”| Property | Type | Description |
|---|---|---|
icon | string | FontAwesome icon class |
label | string | Indicator text |
color | string | Icon color (CSS color value) |
tooltip | string | Hover tooltip text |
onAttach | function | Called with the DOM element when the widget is attached |
Custom properties
Section titled “Custom properties”| Property | Type | Description |
|---|---|---|
render | function | Receives the location string and returns an HTML string |
onAttach | function | Called with the DOM element when the widget is attached |
Managing widgets
Section titled “Managing widgets”Get registered widgets
Section titled “Get registered widgets”// Get all widgets at a specific pointconst hudButtons = CALENDARIA.api.getRegisteredWidgets('hud.buttons.right');
// Get widget replacing a specific elementconst weatherWidget = CALENDARIA.api.getWidgetByReplacement('weather-indicator');Refresh widgets
Section titled “Refresh widgets”Force all widgets to re-render:
CALENDARIA.api.refreshWidgets();Widget-related hooks are documented in Hooks > Widget Hooks:
calendaria.widgetRegistered- Fired when a widget is registeredcalendaria.widgetsRefresh- Fired when widgets are refreshed
CSS styling
Section titled “CSS styling”Each widget receives a class based on its module ID for targeted styling:
/* Style all widgets from your module */.widget-my-module { /* Your styles */}
/* Style a specific widget */.widget-my-module[data-widget-id='my-module.my-button'] { /* Your styles */}The data-widget-id attribute holds the fully-qualified id (moduleId.id).
Example: complete module integration
Section titled “Example: complete module integration”Hooks.once('calendaria.ready', ({ api }) => { // Add a button to show party resources api.registerWidget('my-module', { id: 'party-resources', type: 'button', insertAt: 'hud.buttons.right', icon: 'fas fa-coins', tooltip: 'Party Resources', onClick: () => openResourceTracker() });
// Add a custom widget api.registerWidget('my-module', { id: 'party-gold', type: 'custom', insertAt: 'hud.indicators', render: (location) => { const gold = getPartyGold(); return ` <span class="indicator-icon"><i class="fas fa-coins" style="color: gold;"></i></span> <span class="indicator-label">${gold} gp</span> `; } });
// Update the widget when gold changes Hooks.on('updatePartyGold', () => { api.refreshWidgets(); });});