Skip to main content
skill CX Codex

ue-component-model — Claude Code skill: what it does, how to install

Configures AEM Edge Delivery Services blocks for Universal Editor. Reads block JS and CSS, then generates or updates the required JSON models.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add adobe/skills --skill ue-component-model -a claude-code
Open on GitHub

What ue-component-model does

The skill configures AEM Edge Delivery Services blocks for Universal Editor authoring. It inspects blocks/<name>/<name>.js and blocks/<name>/<name>.css before touching any configuration. The analysis tracks DOM queries like picture or link elements in decorate(block) to understand expected content and row structures.

From those findings, the skill populates three files: component-definition.json to register the block, component-models.json for property fields, and component-filters.json to allow placement. If the repository relies on distributed configuration, it writes a single blocks/<name>/_<name>.json file instead. It also handles semantic collapsing, such as pairing image with imageAlt.

A missing entry in the section filter means the block remains invisible to authors in the Universal Editor palette. That makes validating component-filters.json mandatory before deploying the changes.

What it helps with

  • generate Universal Editor JSON configurations for new EDS blocks
  • map block JavaScript content queries to property panel fields
  • configure container blocks with repeatable child items
  • register block identifiers in section component filters

Example prompts for the agent

  • Generate Universal Editor configuration for blocks/hero/hero.js
  • Add style variant options to component-models.json for the teaser block
  • Create a distributed _cards.json configuration for a container block

How to install ue-component-model

1Skills CLI (Vercel)

npx skills add adobe/skills --skill ue-component-model -a claude-code

2Manually: put the files in place

~/.claude/skills/ue-component-model/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/ue-component-model/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about ue-component-model

How do I install ue-component-model in Claude Code?

Run npx skills add adobe/skills --skill ue-component-model -a claude-code in your terminal to install the skill for Claude Code.

What does ue-component-model do?

It analyzes block implementation code and creates component-definition.json, component-models.json, and component-filters.json for AEM Universal Editor.

Does it support distributed block configurations?

Yes. When it detects blocks/<name>/_<name>.json files, it builds a single distributed file containing definitions, models, and filters while updating the main section filter.

Source text

SKILL.md · Apache-2.0
---
name: ue-component-model
description: Use this when the user mentions component models, component definitions, component filters, block configuration for the Universal Editor, UE block setup, adding a new block to UE, configuring block properties or block authoring fields, or wants to create an EDS/Franklin block with Universal Editor support, modify block fields, or add a block to the section filter. Covers creating and editing the three JSON files that control how AEM Edge Delivery Services blocks appear and behave in the Universal Editor — component-definition.json, component-models.json, and component-filters.json.
license: Apache-2.0
---

# Universal Editor Component Model Configuration

This skill helps you create or edit the three JSON configuration files that control how AEM Edge Delivery Services (EDS) blocks appear and behave in the Universal Editor (UE):

1. **component-definition.json** — Registers blocks in the UE component palette
2. **component-models.json** — Defines property panel fields for each block
3. **component-filters.json** — Controls where blocks can be placed

## When to Use

- Creating a new block that needs UE authoring support
- Adding/modifying fields on an existing block's property panel
- Registering a block so it appears in the author's component palette
- Setting up container blocks with child items
- Adding block variants/style options

## Workflow

### Step 1: Understand the Block

Before generating any configuration, read and analyze:

1. **The block's JS file** (`blocks/<name>/<name>.js`) — understand what content the `decorate(block)` function expects:
   - What does it read from the block div? (images, links, text, classes)
   - Does it expect a flat structure or rows of items?
   - Does it use `block.querySelector('a')` (links/URLs), `block.querySelector('picture')` (images), etc.?
   - Does it check for CSS classes/variants?

2. **The block's CSS file** (`blocks/<name>/<name>.css`) — look for variant-specific styles.

3. **Existing config** — check if entries already exist:
   - Search `component-definition.json` for the block ID
   - Search `component-models.json` for the model ID
   - Search `component-filters.json` for the block in the `section` components list
   - Check for a `blocks/<name>/_<name>.json` distributed config file

### Step 2: Determine the Block Type

Based on the JS analysis:

- **Simple block**: One component with its own fields. Most blocks are this type.
  - Example: Hero, Embed — single model, no children

- **Container block**: Has repeatable child items (cards, slides, tabs).
  - Clue: JS iterates over `block.children` or creates items from rows
  - Needs: container definition + item definition + filter

- **Key-value block**: Configuration-style block (2-column key-value pairs).
  - Clue: Each property is independent, not a grid of content
  - Needs: `"key-value": true` in template

### Step 3: Design the Model Fields

Map the block's content expectations to component model fields. Read [references/field-types.md](references/field-types.md) for the full field type reference.

**Common field mappings:**

| Block expects... | Use component type | Notes |
|-----------------|-------------------|-------|
| An image | `reference` (name: `image`) | Pair with `text` field named `imageAlt` |
| A URL/link | `aem-content` (name: `link` or `url`) | For page links and external URLs |
| Rich text content | `richtext` | For formatted text with headings, lists, links |
| Plain text (single line) | `text` | For titles, labels, short strings |
| Plain text (multi-line) | `textarea` | For descriptions, notes, long text without formatting |
| Heading level choice | `select` with h1-h6 options | Name it `titleType` to auto-collapse with title |
| Style variants | `multiselect` (name: `classes`) | Values become CSS classes on block div |
| Multiple toggles | `checkbox-group` | For multiple independent boolean options |
| Boolean toggle | `boolean` | For show/hide options |
| Number value | `number` | For counts, limits |
| Content Fragment | `aem-content-fragment` | For CF-driven blocks |
| Experience Fragment | `aem-experience-fragment` | For reusable content+layout fragments |
| Content tags | `aem-tag` | For categorization via AEM tag picker |

**Field naming rules (semantic collapsing):**
- `image` + `imageAlt` → collapsed into `<picture><img alt="...">`
- `link` + `linkText` + `linkTitle` + `linkType` → collapsed into `<a href="..." title="...">text</a>` with optional class
- `title` + `titleType` → collapsed into `<h2>title</h2>` (level from titleType)
- Fields prefixed with `group_` (underscore separator) are grouped into a single cell

### Step 4: Generate the Configuration

Generate entries for all three files. The approach depends on whether the project uses centralized or distributed config.

**Check for distributed config pattern**: If the block directory contains `_<blockname>.json` files (e.g., `blocks/hero/_hero.json`), create a distributed config file instead of editing the central files.

#### For Centralized Config (editing the three root JSON files):

**component-definition.json** — Add to the `"Blocks"` group's `components` array:

```json
{
  "title": "<Block Display Name>",
  "id": "<block-id>",
  "plugins": {
    "xwalk": {
      "page": {
        "resourceType": "core/franklin/components/block/v1/block",
        "template": {
          "name": "<Block Name>",
          "model": "<model-id>"
        }
      }
    }
  }
}
```

For container blocks, add both the container AND item definitions. The container gets `"filter"` instead of `"model"`, and the item uses `"core/franklin/components/block/v1/block/item"` as resourceType.

For key-value blocks, add `"key-value": true` to the template.

Template can include default values for any model field (e.g., `"titleType": "h3"`, `"classes": ["light"]`).

**component-models.json** — Add a new model entry:

```json
{
  "id": "<model-id>",
  "fields": [
    {
      "component": "<field-type>",
      "name": "<property-name>",
      "label": "<Display Label>",
      "valueType": "string"
    }
  ]
}
```

**component-filters.json** — Add the block ID to the `section` filter's `components` array. For container blocks, also add a new filter entry defining allowed children.

#### For Distributed Config (creating `blocks/<name>/_<name>.json`):

Create a single file with all three configs:

```json
{
  "definitions": [ ... ],
  "models": [ ... ],
  "filters": [ ... ]
}
```

Still add the block to the `section` filter in the central `component-filters.json`.

### Step 5: Validate

After generating the config, verify:

1. **ID consistency**: The `id` in the definition matches what's used in `component-filters.json`. The `template.model` value matches the `id` in `component-models.json`.
2. **Filter registration**: The block's ID appears in the `section` filter's `components` array (otherwise authors can't add it to pages).
3. **Field names match block JS**: The `name` properties in the model fields should produce HTML that the block's `decorate()` function can consume.
4. **Semantic collapsing**: Paired fields use correct suffixes (e.g., `image`/`imageAlt`, not `image`/`altText` unless intentional).
5. **Valid JSON**: All three files remain valid JSON after edits.
6. **No duplicate IDs**: No model or filter ID conflicts with existing entries.

## Reference Files

For detailed information, read these reference files as needed:

- **[references/architecture.md](references/architecture.md)** — How the three files connect, the full AEM→Markdown→HTML pipeline, resource types, field naming conventions, semantic collapsing rules, and RTE filter configuration
- **[references/field-types.md](references/field-types.md)** — Complete reference for all 17 field component types (`text`, `textarea`, `richtext`, `reference`, `aem-content`, `aem-content-fragment`, `aem-experience-fragment`, `aem-tag`, `select`, `multiselect`, `checkbox-group`, `radio-group`, `boolean`, `number`, `date-time`, `container`, `tab`), valueType constraints, required properties, field properties, validation types, conditional fields, and option formats
- **[references/examples.md](references/examples.md)** — Real examples showing Hero (simple), Embed (simple with URL), Cards (container), Teaser (variants), Product Details (key-value), Article (content fragment), Section configuration, Metadata (textarea), Feature Toggles (checkbox-group), and RTE filter configuration

## Common Pitfalls

- **Forgetting to add to section filter**: The block won't appear in the author's add menu unless it's in the `section` filter's components list.
- **Wrong resourceType**: Almost all custom blocks use `core/franklin/components/block/v1/block`. Don't invent custom resource types.
- **Mismatched model/filter IDs**: The `template.model` must exactly match the model `id`, and `template.filter` must exactly match the filter `id`.
- **Choosing the wrong text field type**: Use `text` for single-line strings, `textarea` for multi-line plain text, and `richtext` for formatted content. For URLs and page links, use `aem-content` so authors get the content picker.
- **Wrong valueType**: Most components enforce a specific `valueType` (e.g., `boolean` must use `"boolean"`, `number` must use `"number"`, `checkbox-group` must use `"string[]"`). Always include `valueType` and check the field-types reference for the enforced value.
- **Container without filter**: Container blocks need a `filter` (not a `model`) in their template, and a corresponding filter entry in component-filters.json.

© adobe · Apache-2.0 · adobe/skills

Similar skills

Everything for Frontend and UI →

From the same set46

content-driven-development A skill for AEM Edge Delivery Services work: find or create test content first, then write the code. Useful for blocks, styling and scripts.js changes. CX Codex +1 1,600installs block-inventory Surveys local AEM Edge Delivery Services blocks and searches the Block Collection to inform content modeling decisions during page imports. CX Codex +1 1,600installs building-blocks A skill for implementing AEM Edge Delivery Services blocks and core changes: it creates block folders, writes decorate functions, scopes CSS. Runs from content-driven-development at the implementation step. CX Codex +1 1,600installs code-review Audits AEM Edge Delivery Services code against Adobe standards before commits or during pull request reviews. CX Codex +1 1,600installs create-site Walks an agent through a brand-new AEM Edge Delivery site: repo from the boilerplate, aem-code-sync, starter DA pages, live preview link. CX Codex +1 1,500installs ensure-agents-md Creates AGENTS.md and CLAUDE.md at the root of an AEM 6.5 LTS project when they are missing. It adapts project guidance from pom.xml and the module structure. CX Codex +1 1,100installs da-auth Fetches an Adobe IMS access token into DA_TOKEN so your agent can call admin.da.live without a manual copy-paste. CX Codex +1 1,000installs create-component Generates complete AEM components with HTL markup, Sling Models, dialogs, and tests. Extends Core Components and converts Figma designs into code. CX Codex +1 1,000installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor