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