Widget Templates
Create reusable widget templates that AI can instantiate with simple parameters.
Overview
Widget templates let you define complex component structures once and have the AI reuse them with different parameters. Instead of the AI writing out full component markup every time, it can use a simple <widget> tag with props.
Creating a Widget Template
Define a widget template with a type, name, template string, and props schema:
import { WidgetTemplate } from "melony";
const weatherWidget: WidgetTemplate = {
type: "weather",
name: "Weather Card",
description: "Display weather information",
template: `<card title="{{location}} Weather">
<row gap="md" align="center">
<text value="{{temperature}}°F" size="xl" weight="bold" />
<badge label="{{condition}}" variant="primary" />
</row>
<text value="{{description}}" color="muted" />
<button
label="Refresh"
variant="outline"
action='{"type":"refresh-weather","location":"{{location}}"}'
/>
</card>`,
props: [
{ name: "location", type: "string", required: true },
{ name: "temperature", type: "number", required: true },
{ name: "condition", type: "string", required: true },
{ name: "description", type: "string", required: false },
],
};Registering Widgets
Pass your widget templates to MelonyProvider:
import { MelonyProvider } from "melony";
const widgets = [weatherWidget, stockWidget, taskWidget];
function App() {
return (
<MelonyProvider widgets={widgets}>
{/* Your components */}
</MelonyProvider>
);
}How AI Uses Widgets
Once registered, the AI can use widgets with a simple tag:
Here's the weather:
<widget
type="weather"
location="San Francisco"
temperature="68"
condition="Sunny"
description="Perfect day for a walk!"
/>
The temperature feels comfortable.This renders the full template with the provided parameters substituted.
Template Variables
Templates use {{variableName}} syntax for variable substitution:
template: `<card title="{{title}}">
<text value="{{content}}" />
{{#if showButton}}
<button label="{{buttonLabel}}" />
{{/if}}
</card>`• {{variable}} - Simple variable substitution
• All props are available as variables in the template
• Variables can be used in any attribute or text content
Multiple Widget Example
Here's a complete example with multiple widgets:
import { MelonyProvider, WidgetTemplate } from "melony";
const widgets: WidgetTemplate[] = [
{
type: "weather",
name: "Weather Card",
template: `<card title="{{location}}">
<text value="{{temperature}}°F" size="lg" weight="bold" />
<badge label="{{condition}}" />
</card>`,
props: [
{ name: "location", type: "string", required: true },
{ name: "temperature", type: "number", required: true },
{ name: "condition", type: "string", required: true },
],
},
{
type: "stock",
name: "Stock Quote",
template: `<card title="{{symbol}}">
<row gap="sm">
<text value="${{price}}" size="xl" weight="bold" />
<badge
label="{{change > 0 ? '+' : ''}}{{change}}%"
variant="{{change > 0 ? 'success' : 'destructive'}}"
/>
</row>
</card>`,
props: [
{ name: "symbol", type: "string", required: true },
{ name: "price", type: "number", required: true },
{ name: "change", type: "number", required: true },
],
},
{
type: "task",
name: "Task Item",
template: `<card>
<row gap="md" align="center">
<text value="{{title}}" flex="1" />
<badge label="{{status}}" />
<button
label="Complete"
variant="outline"
action='{"type":"complete-task","id":"{{id}}"}'
/>
</row>
</card>`,
props: [
{ name: "id", type: "string", required: true },
{ name: "title", type: "string", required: true },
{ name: "status", type: "string", required: true },
],
},
];
export default function App() {
return (
<MelonyProvider widgets={widgets}>
{/* Your app */}
</MelonyProvider>
);
}Widget Props Schema
Each widget prop has the following structure:
interface WidgetProp {
name: string; // Prop name
type: string; // Type: "string", "number", "boolean", etc.
required: boolean; // Whether prop is required
description?: string; // Optional description
default?: any; // Optional default value
}Benefits of Widget Templates
- Consistency: Ensure UI components have consistent styling and structure
- Reusability: Define complex components once, reuse many times
- Simplicity: AI uses simple parameters instead of writing full markup
- Maintainability: Update widget templates in one place
- Type Safety: Define prop schemas to ensure correct usage
Best Practices
- Keep widget templates focused on a single purpose
- Use descriptive type names (e.g., "weather-card" not "widget1")
- Provide clear descriptions for each widget and prop
- Mark props as required only when truly necessary
- Use default values for optional props when sensible
- Test widgets with different parameter combinations