Development
007-properties-panel-web-components - Claude MCP Skill
<objective>
SEO Guide: Enhance your AI agent with the 007-properties-panel-web-components tool. This Model Context Protocol (MCP) server allows Claude Desktop and other LLMs to <objective>... Download and configure this skill to unlock new capabilities for your AI workflow.
Documentation
SKILL.md<objective>
Build the interactive Properties Panel UI using Web Components with 2-way data binding between the schema-driven form and Monaco editor.
This phase creates the client-side interactivity layer: custom elements (<prop-editor>, <prop-field>) that handle form state, real-time Monaco synchronization, and dirty state trackingβall without requiring a JavaScript framework.
This enables users to edit Block properties via both the visual form and raw JSON, with changes instantly reflected in both views.
</objective>
<context>
**Previous Phase Deliverables:**
- Schema-driven form renderer exists (schema_form.rs)
- Forms are server-rendered with data-path attributes on each field
- Test route at /admin/schema-test/header displays HeaderProps form
**Current State:**
- Monaco editor exists and is integrated (from git history: admin-index.css, monaco.js)
- Forms are static HTML (no interactivity yet)
- No connection between form fields and Monaco JSON
**End Goal (This Phase):**
Web Components that provide:
- Form field state management
- 2-way binding: Form changes β Monaco JSON, Monaco changes β Form fields
- Dirty state tracking (unsaved changes indicator)
- Foundation for Phase 3's publish workflow
**Why This Matters:**
This creates a professional editor experience where users can work in their preferred mode (visual form or code) while maintaining a single source of truth. Changes propagate instantly without page reloads.
</context>
<requirements>
**Agent Invocation:**
Use @agent-graydon-rust-engineer with ALL available skills:
- web-components-architecture (Custom Elements v1, Declarative Shadow DOM, handleEvent)
- javascript-pragmatic-rules (async operations, V8 optimization, memory management)
- maud-components-patterns (server-side rendering with Web Components)
- rust-core-patterns (type-safe component architecture)
**CRITICAL:** Use Web Components architecture skill for ALL JavaScript. Follow these patterns:
- Custom Elements v1 API with Declarative Shadow DOM
- Attribute-driven state (no props drilling)
- handleEvent pattern for event handling
- Zero DOM selection (NO querySelector, NO innerHTML)
- Pure web platform APIs only (NO external libraries)
**Technical Requirements:**
1. **Web Component: `<prop-editor>`**
- Container component that manages the entire properties panel
- Attributes:
- `schema` - JSON Schema (from schemars)
- `initial-value` - Current Block props as JSON string
- State:
- Current form values (object matching schema structure)
- Dirty flag (has unsaved changes)
- Responsibilities:
- Initialize Monaco editor in JSON mode
- Sync form β Monaco on field changes
- Sync Monaco β form on editor changes
- Emit custom events: `prop-change`, `prop-dirty`, `prop-clean`
- Methods:
- `getValue()` - Return current props as JSON
- `setValue(json)` - Update both form and Monaco
- `reset()` - Revert to initial value
2. **Web Component: `<prop-field>`**
- Individual form field wrapper
- Attributes:
- `path` - Property path (e.g., "button.text")
- `type` - Schema type ("string", "boolean", "number")
- `value` - Current value
- Responsibilities:
- Wrap existing input/checkbox components
- Listen for user input events
- Dispatch change event to parent <prop-editor>
- Update own value when parent calls setValue()
- Use handleEvent pattern for all event listeners
3. **2-Way Binding Architecture**
```
User types in form input
β
<prop-field> dispatches 'field-change' event
β
<prop-editor> updates internal state
β
<prop-editor> updates Monaco JSON
β
Monaco editor displays updated JSON
User edits Monaco JSON
β
Monaco onChange event
β
<prop-editor> parses JSON
β
<prop-editor> updates form fields via setValue()
β
<prop-field> elements reflect new values
```
4. **Dirty State Tracking**
- Compare current value with initial-value attribute
- Add visual indicator (e.g., orange border, "Unsaved changes" text)
- Emit `prop-dirty` event when changes detected
- Emit `prop-clean` event when reverted to initial
5. **Server Integration**
- Update schema_form.rs to wrap rendered form in <prop-editor>
- Inject schema and initial-value attributes server-side
- Render <prop-field> wrappers around input/checkbox components
- Include Web Component JavaScript in page <head>
6. **Monaco Integration**
- Reuse existing Monaco editor setup
- Configure for JSON editing mode
- Add schema validation (use the generated JSON Schema)
- Pretty-print JSON formatting
- Syntax highlighting for properties
</requirements>
<implementation>
**Design Principles:**
1. **Web Components Best Practices:**
- Extend HTMLElement, NOT framework components
- Use attributeChangedCallback for reactive updates
- Implement connectedCallback/disconnectedCallback for lifecycle
- Use handleEvent pattern for memory-efficient event handling
- Declarative Shadow DOM for encapsulation (if needed)
2. **State Management Pattern:**
```javascript
class PropEditor extends HTMLElement {
#state = { values: {}, dirty: false };
handleEvent(event) {
switch(event.type) {
case 'field-change': this.#handleFieldChange(event);
case 'monaco-change': this.#handleMonacoChange(event);
}
}
#syncFormToMonaco() { /* update Monaco JSON */ }
#syncMonacoToForm() { /* update form fields */ }
}
```
3. **Data Flow:**
- Single source of truth: <prop-editor>'s internal state
- Form fields are "controlled components" (React pattern in vanilla JS)
- Monaco editor is also controlled by <prop-editor>
- Deep equality check prevents infinite update loops
4. **Why This Approach:**
- Web Components: Native, no build step, framework-agnostic
- handleEvent: Memory-efficient, better performance than arrow functions
- Attribute-driven: Server can hydrate initial state easily
- Custom events: Loose coupling, easy to extend
**What to Avoid:**
- β NO React/Vue/Angular (Web Components only)
- β NO npm/webpack (vanilla ES modules)
- β NO querySelector inside components (pass refs via attributes if needed)
- β NO innerHTML (security risk, breaks existing components)
- β NO global state (encapsulate in <prop-editor>)
</implementation>
<output>
Create/modify these files:
1. `./website/assets/components/prop-editor.js` - Main editor component
2. `./website/assets/components/prop-field.js` - Field wrapper component
3. `./website/assets/components/index.js` - Register all components
4. `./website/src/core/schema_form.rs` - Update to wrap form in Web Components
5. `./website/src/pages/admin/schema_test.rs` - Include component scripts
6. `./website/assets/components/prop-editor.css` - Styling for dirty states, layout
All JavaScript must follow the web-components-architecture skill patterns.
All files should follow existing project conventions from @CLAUDE.md
</output>
<verification>
Before declaring complete, verify:
1. **Component Registration:**
- Custom elements are registered: `customElements.define('prop-editor', PropEditor)`
- No console errors on page load
- Components appear in browser DevTools as custom elements
2. **Form β Monaco Sync:**
- Type in a form input field
- Monaco editor JSON updates in real-time
- JSON structure matches schema (nested objects preserved)
- No lag or debouncing issues
3. **Monaco β Form Sync:**
- Edit JSON directly in Monaco (e.g., change "headline": "New Text")
- Form field updates to show "New Text"
- Works for nested properties (button.text)
- Invalid JSON shows validation error (doesn't crash)
4. **Dirty State:**
- Initially shows "No unsaved changes"
- After editing, shows "Unsaved changes" indicator
- Visual feedback (e.g., orange border on form)
- Reverts to clean when reset() is called
5. **Browser Compatibility:**
- Test in Chrome/Safari (Web Components support)
- No framework dependencies in network tab
- JavaScript follows javascript-pragmatic-rules (no memory leaks)
6. **Integration with Existing UI:**
- Existing input/checkbox components still render correctly
- Styles don't conflict
- Server-rendered HTML hydrates properly
</verification>
<success_criteria>
- β
Web Components defined using Custom Elements v1 API
- β
2-way binding works: Form β Monaco JSON sync in real-time
- β
Dirty state tracking with visual indicator
- β
Zero framework dependencies (vanilla JS only)
- β
Follows web-components-architecture patterns (handleEvent, no querySelector)
- β
Test route demonstrates full interactivity with HeaderProps
- β
Code follows javascript-pragmatic-rules (memory-safe, performant)
</success_criteria>Signals
Information
- Repository
- matthewharwood/engmanager.xyz
- Author
- matthewharwood
- Last Sync
- 3/12/2026
- Repo Updated
- 1/31/2026
- Created
- 1/17/2026
Reviews (0)
No reviews yet. Be the first to review this skill!
Related Skills
upgrade-webkit
Upgrade Bun's Webkit fork to the latest upstream version of Webkit.
upgrade-nodejs
Upgrading Bun's Self-Reported Node.js Version
cursorrules
CrewAI Development Rules
cn-check
Install and run the Continue CLI (`cn`) to execute AI agent checks on local code changes. Use when asked to "run checks", "lint with AI", "review my changes with cn", or set up Continue CI locally.
Related Guides
Bear Notes Claude Skill: Your AI-Powered Note-Taking Assistant
Learn how to use the bear-notes Claude skill. Complete guide with installation instructions and examples.
Mastering tmux with Claude: A Complete Guide to the tmux Claude Skill
Learn how to use the tmux Claude skill. Complete guide with installation instructions and examples.
OpenAI Whisper API Claude Skill: Complete Guide to AI-Powered Audio Transcription
Learn how to use the openai-whisper-api Claude skill. Complete guide with installation instructions and examples.