Skip to main content
Glama

scaffold_component

Generate component templates for forms, lists, detail views, cards, modals, and navigation elements with optional features like validation, internationalization, state management, data fetching, animations, and drag-and-drop functionality.

Instructions

Generate a NoJS component template following framework conventions

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
typeYesComponent type to scaffold
featuresNoOptional features to include: "validation", "i18n", "state", "fetch", "animation", "dnd"

Implementation Reference

  • The `scaffold_component` tool is defined and implemented directly in `src/tools/index.ts`. It takes a `type` and an optional list of `features`, and returns a string containing a scaffolded HTML template for a NoJS component.
        // ── scaffold_component ──
        server.tool(
            "scaffold_component",
            "Generate a NoJS component template following framework conventions",
            {
                type: z
                    .enum(["form", "list", "detail", "card", "modal", "nav"])
                    .describe("Component type to scaffold"),
                features: z
                    .array(z.string())
                    .optional()
                    .describe(
                        'Optional features to include: "validation", "i18n", "state", "fetch", "animation", "dnd"'
                    ),
            },
            async ({ type, features = [] }) => {
                const templates: Record<string, string> = {
                    form: `<div state="{ email: '', password: '', loading: false }">
      <h2>Login</h2>
      <form validate on:submit.prevent="loading = true">
        <div class="field">
          <label>Email</label>
          <input model="email" type="email" validate="required,email"
                 error-required="Email is required" error-email="Invalid email">
        </div>
        <div class="field">
          <label>Password</label>
          <input model="password" type="password" validate="required"
                 error-required="Password is required">
        </div>
        <p if="$form.firstError" class="error" bind="$form.firstError"></p>
        <button type="submit" class-disabled="!$form.valid || loading">
          <span hide="loading">Submit</span>
          <span show="loading">Loading...</span>
        </button>
      </form>
    </div>`,
    
                    list: `<div state="{ search: '' }">
      <input model="search" placeholder="Search...">
      <div get="/items" as="items">
        <div each="item in items" key="item.id"
             animate="fadeIn" animate-stagger="50">
          <h3 bind="item.title"></h3>
          <p bind="item.description | truncate(100)"></p>
        </div>
        <p if="items.length === 0">No items found.</p>
      </div>
    </div>`,
    
                    detail: `<div get="/items/{$route.params.id}" as="item">
      <template if="item">
        <h1 bind="item.title"></h1>
        <p bind="item.description"></p>
        <span bind="item.createdAt | relative"></span>
      </template>
      <template else>
        <p>Loading...</p>
      </template>
    </div>`,
    
                    card: `<div class="card" state="{ expanded: false }">
      <div class="card-header">
        <h3 bind="title"></h3>
        <button on:click="expanded = !expanded">
          <span hide="expanded">▸</span>
          <span show="expanded">▾</span>
        </button>
      </div>
      <div class="card-body" show="expanded" animate="slideDown">
        <p bind="description"></p>
      </div>
    </div>`,
    
                    modal: `<div state="{ open: false }">
      <button on:click="open = true">Open Modal</button>
      <div class="modal-overlay" show="open" on:click.self="open = false"
           animate-enter="fadeIn" animate-leave="fadeOut">
        <div class="modal-content" animate-enter="slideUp" animate-leave="slideDown">
          <div class="modal-header">
            <h2>Modal Title</h2>
            <button on:click="open = false">×</button>
          </div>
          <div class="modal-body">
            <p>Modal content goes here.</p>
          </div>
          <div class="modal-footer">
            <button on:click="open = false">Close</button>
          </div>
        </div>
      </div>
    </div>`,
    
                    nav: `<nav class="navbar">
      <a route="/" class="logo">App</a>
      <div class="nav-links">
        <a route="/" route-active="active">Home</a>
        <a route="/features" route-active="active">Features</a>
        <a route="/about" route-active="active">About</a>
        <a route="/contact" route-active="active">Contact</a>
      </div>
    </nav>`,
                };
    
                let html = templates[type] || templates["card"];
                let description = `NoJS ${type} component template`;
    
                // Add feature hints
                const featureNotes: string[] = [];
                if (features.includes("i18n")) {
                    featureNotes.push(
                        "Add t=\"key\" to text elements for i18n support"
                    );
                }
                if (features.includes("animation")) {
                    featureNotes.push(
                        'Add animate="fadeIn" or transition="slide" for animations'
                    );
                }
                if (features.includes("dnd")) {
                    featureNotes.push(
                        "Add drag/drop attributes for drag-and-drop support"
                    );
                }
    
                let output = `## Generated ${type} template\n\n\`\`\`html\n${html}\n\`\`\`\n`;
                if (featureNotes.length > 0) {
                    output += `\n## Feature Notes\n\n${featureNotes.map((n) => `- ${n}`).join("\n")}\n`;
                }
    
                return {
                    content: [{ type: "text" as const, text: output }],
                };
            }
        );

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ErickXavier/nojs-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server