Skip to content

Widgets

Calendaria provides a widget system for external modules to add custom UI elements to Calendaria applications.


Widgets let module developers:

  • Add custom buttons to the HUD, BigCal, and MiniCal
  • Add custom indicator displays
  • Replace built-in indicators with custom implementations

Widgets can be inserted at these locations:

PointLocationWidget Types
hud.buttons.leftLeft side of HUD barButtons
hud.buttons.rightRight side of HUD barButtons
hud.indicatorsIndicator section of HUD barIndicators
hud.trayTime controls trayButtons
minical.sidebarMiniCal sidebarButtons
bigcal.actionsBigCal action barButtons

Access these via CALENDARIA.api.widgetPoints.


Built-in indicator elements that can be replaced by custom widgets. Replacements apply across all three applications (HUD, MiniCal, BigCal):

Element IDDescription
weather-indicatorWeather condition display
season-indicatorCurrent season display
era-indicatorEra/year display
cycle-indicatorCycle (zodiac, etc.) display

Access these via CALENDARIA.api.replaceableElements.

[!NOTE] When you replace an indicator, the replacement applies wherever that indicator appears in any Calendaria application.


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!');
}
});
});
CALENDARIA.api.registerWidget('my-module', {
id: 'custom-indicator',
type: 'indicator',
insertAt: 'hud.indicators',
render: (container) => {
container.innerHTML = `
<span class="indicator-icon"><i class="fas fa-gem"></i></span>
<span class="indicator-label">Mana: 50</span>
`;
},
onAttach: (element) => {
// Called when widget is added to DOM
},
onDetach: (element) => {
// Called when widget is removed from DOM
}
});
CALENDARIA.api.registerWidget('my-module', {
id: 'custom-weather',
type: 'indicator',
replaces: 'weather-indicator',
render: (container) => {
const weather = CALENDARIA.api.getCurrentWeather();
container.innerHTML = `<span>Custom: ${weather?.label || 'None'}</span>`;
}
});

PropertyTypeDescription
idstringUnique widget identifier within your module
typestring'button' or 'indicator'

One of these is required:

PropertyTypeDescription
insertAtstringWidget point ID from widgetPoints
replacesstringElement ID from replaceableElements
PropertyTypeDescription
iconstringFontAwesome icon class
labelstringButton text (optional)
tooltipstringHover tooltip text
colorstringIcon color (CSS color value)
onClickfunctionClick handler
disabledboolean or functionDisable state or function returning boolean
PropertyTypeDescription
renderfunctionReceives container element, renders content
onAttachfunctionCalled when added to DOM
onDetachfunctionCalled when removed from DOM

// Get all widgets at a specific point
const hudButtons = CALENDARIA.api.getRegisteredWidgets('hud.buttons.right');
// Get widget replacing a specific element
const weatherWidget = CALENDARIA.api.getWidgetByReplacement('weather-indicator');

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 registered
  • calendaria.widgetsRefresh - Fired when widgets are refreshed

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-button'] {
/* Your styles */
}

my-module.js
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 indicator
api.registerWidget('my-module', {
id: 'party-gold',
type: 'indicator',
insertAt: 'hud.indicators',
render: (container) => {
const gold = getPartyGold();
container.innerHTML = `
<span class="indicator-icon"><i class="fas fa-coins" style="color: gold;"></i></span>
<span class="indicator-label">${gold} gp</span>
`;
}
});
// Update indicator when gold changes
Hooks.on('updatePartyGold', () => {
api.refreshWidgets();
});
});