Preferences Template
The widget.preferences-template.json file defines user-configurable settings. Cosmo uses this schema to generate a native UI in the widget's right-click context menu, allowing users to modify widget behavior without interacting with the DOM.
Changes to widget.preferences-template.json are not hot-reloaded. You must restart the development server (npm run dev) for configuration changes to take effect in the Cosmo app.
Schema Overview
Define preferences as a map where keys are identifiers and values are configuration objects.
{
"theme": {
"label": "Theme",
"value": "default",
"order": 1,
"controlType": "select",
"options": ["default", "cosmo", "sunset"],
"optionLabels": ["Default", "Cosmo", "Sunset"]
},
"hideBackground": {
"label": "Hide Background",
"value": false,
"order": 2,
"controlType": "toggle"
}
}Fields
Required
| Field | Type | Description |
|---|---|---|
label | string | The display name in the context menu. |
value | string | boolean | number | The default value. Must match the type expected by controlType. |
order | number | Sort order in the menu (starting from 1). |
controlType | string | The UI component to render. Supported values: "select", "toggle", "calendars". |
Optional
| Field | Type | Description |
|---|---|---|
description | string | Helper text displayed in the menu. |
dividerAfter | boolean | If true, inserts a separator after this item. |
options | array | For select: List of possible values. |
optionLabels | string[] | For select: Display labels corresponding to options. |
widthMultipliers | number[] | Option modifier for width. |
heightMultipliers | number[] | Option modifier for height. |
backgroundBlurRadii | number[] | Option modifier for blur. |
For select controls: options are keys in the preferences object passed to your widget. optionLabels are the user-facing text shown in the right-click menu. See Using Preferences for examples.
Control Types
Select
Renders a dropdown menu.
- Requires:
options. - Recommended:
optionLabels.
{
"theme": {
"label": "Theme",
"value": "default",
"controlType": "select",
"options": ["default", "frosted"],
"optionLabels": ["Default", "Frosted Glass"],
"backgroundBlurRadii": [0, 30]
}
}Toggle
Renders a checkbox or switch.
- Requires:
value(boolean).
{
"hideBackground": {
"label": "Hide Background",
"value": false,
"controlType": "toggle"
}
}Calendars
Renders a calendar picker populated by the user's system calendars.
- Requires:
value(initialize as{}). - Usage: The value is a map of calendar IDs to booleans.
{
"selectedCalendars": {
"label": "Calendars",
"value": {},
"controlType": "calendars"
}
}Option Modifiers
Option modifiers are arrays that map native window properties to each option in a preference. When the user changes a preference value, the corresponding modifier is applied to the widget window.
For select, each modifier value maps to the corresponding index in options. For toggle, the order is [true, false].
widthMultipliers & heightMultipliers
Multiply the widget's base width and height based on the selected preference value. The base multiplier is 1 for both.
{
"layout": {
"label": "Size",
"value": "regular",
"controlType": "select",
"options": ["regular", "wide", "mini"],
"optionLabels": ["Regular", "Wide", "Mini"],
"widthMultipliers": [1, 1.5, 1],
"heightMultipliers": [1, 1, 0.5]
}
}Selecting wide increases width by 50%. Selecting mini reduces height to 50%.
backgroundBlurRadii
Sets the background blur radius based on the selected preference value. This overrides the static backgroundBlurRadius in widget.config.json.
{
"blur": {
"label": "Blur",
"value": "none",
"controlType": "select",
"options": ["none", "heavy"],
"optionLabels": ["None", "Heavy"],
"backgroundBlurRadii": [0, 50]
}
}Selecting heavy applies a blur radius of 50.
Blur effects require the widget's CSS background to be semi-transparent. The blur is applied to the native window behind the web content.
Using Preferences
Cosmo injects preference values into your widget at runtime. They are passed as the first argument to the exported widget() function.
The widget() function is called whenever preferences change, and new preferences data is passed on each call. The preferences parameter is an object where keys match the preference identifiers from your template, and values are the current preference values.
import './style.css'
export default function widget(preferences, widgetData) {
// preferences is an object like:
// {
// "theme": "cosmo",
// "hideBackground": true
// }
const root = ensureRoot();
root.innerHTML = '';
const container = document.createElement('div');
container.className = `
theme-${preferences.theme}
${preferences.hideBackground ? 'hide-background' : ''}
`;
container.textContent = 'Your widget content goes here.';
root.appendChild(container);
}
function ensureRoot() {
let el = document.querySelector('#widget-root');
if (!el) {
el = document.createElement('div');
el.id = 'widget-root';
document.body.appendChild(el);
}
return el;
}export default function Widget({ preferences, widgetData }) {
// preferences is an object like:
// {
// "theme": "cosmo",
// "hideBackground": true
// }
return (
<div className={`
theme-${preferences.theme}
${preferences.hideBackground ? 'hide-background' : ''}
`}>
<div className="content">
Your widget content goes here.
</div>
</div>
)
}<script setup>
// preferences is an object like:
// {
// "theme": "cosmo",
// "hideBackground": true
// }
defineProps({
preferences: {
type: Object,
required: true
}
})
</script>
<template>
<div :class="[
`theme-${preferences.theme}`,
{ 'hide-background': preferences.hideBackground }
]">
<div class="content">
Your widget content goes here.
</div>
</div>
</template>The template file is only read when a widget is first created or installed. Modifying the template file after installation won't affect existing widget instances.