| name | custom-elements |
| description | Define and use custom HTML elements. Use when creating new components, defining custom tags, or using project-specific elements beyond standard HTML5. |
| allowed-tools | Read, Write, Edit, Bash |
Custom Elements Skill
This skill provides guidance for defining and using custom HTML elements in this project.
Two Definition Systems
| System | File | Purpose |
|---|---|---|
| HTML Validation | .claude/schemas/elements.json |
Validates custom elements in HTML (html-validate) |
| Custom Elements Manifest | custom-elements.json |
Documents components for IDEs, Storybook, docs |
Both are recommended - elements.json for build-time HTML validation, CEM for runtime tooling.
See MANIFEST.md for Custom Elements Manifest generation.
Using Existing Elements
Check .claude/schemas/elements.json for defined custom elements:
| Element | Type | Purpose |
|---|---|---|
product-card |
Block | Product display with sku, price attributes |
icon-element |
Void | Self-closing icon with required name attribute |
user-avatar |
Void | Avatar with required src, alt and optional size |
status-badge |
Inline | Status indicator with type (success/warning/error/info) |
data-table |
Block | Data table with source, sortable attributes |
nav-menu |
Block | Navigation with orientation (horizontal/vertical) |
Usage Examples
<!-- Product card with attributes -->
<product-card sku="ABC123" price="29.99">
<h2>Product Name</h2>
<p>Product description here.</p>
</product-card>
<!-- Void element (self-closing) -->
<icon-element name="star"/>
<user-avatar src="/avatar.jpg" alt="John Doe" size="medium"/>
<!-- Inline element -->
<p>Status: <status-badge type="success">Active</status-badge></p>
<!-- Block elements -->
<nav-menu orientation="horizontal">
<ul>
<li><a href="/">Home</a></li>
</ul>
</nav-menu>
<data-table source="/api/users" sortable="">
<!-- Table content -->
</data-table>
Ad-hoc Custom Elements
For one-off custom elements not worth defining in .claude/schemas/elements.json, use the x-* prefix:
<x-highlight>Important text</x-highlight>
<x-tooltip data-text="Help text">Hover me</x-tooltip>
<x-badge>New</x-badge>
The x-* pattern is excluded from validation by default.
Defining New Elements
Using Slash Command
/add-element my-widget
Manual Definition
Add to .claude/schemas/elements.json:
{
"my-element": {
"flow": true,
"phrasing": false,
"permittedContent": ["@flow"],
"attributes": {
"required-attr": { "required": true },
"optional-attr": { "required": false }
}
}
}
Element Schema Reference
Content Model
| Property | Values | Description |
|---|---|---|
flow |
boolean | Can appear where flow content is expected |
phrasing |
boolean | Can appear where phrasing content is expected |
void |
boolean | Self-closing element (no content) |
permittedContent |
array | What content is allowed inside |
Permitted Content Values
@flow- Flow content (most elements)@phrasing- Phrasing content (inline elements)@interactive- Interactive elements["p", "div"]- Specific elements only
Attribute Definitions
{
"attributes": {
"name": {
"required": true // Must be present
},
"type": {
"required": false,
"enum": ["a", "b", "c"] // Restricted values
},
"enabled": {
"boolean": true // Boolean attribute
}
}
}
Complete Examples
Block Element
{
"card-component": {
"flow": true,
"phrasing": false,
"permittedContent": ["@flow"],
"attributes": {
"variant": {
"required": false,
"enum": ["default", "outlined", "elevated"]
},
"clickable": {
"boolean": true
}
}
}
}
Usage:
<card-component variant="elevated" clickable="">
<h2>Card Title</h2>
<p>Card content</p>
</card-component>
Void Element
{
"loading-spinner": {
"void": true,
"flow": true,
"phrasing": true,
"attributes": {
"size": {
"enum": ["small", "medium", "large"]
}
}
}
}
Usage:
<loading-spinner size="medium"/>
Inline Element
{
"price-tag": {
"flow": true,
"phrasing": true,
"permittedContent": ["@phrasing"],
"attributes": {
"currency": {
"required": false,
"enum": ["USD", "EUR", "GBP"]
}
}
}
}
Usage:
<p>Price: <price-tag currency="USD">29.99</price-tag></p>
Naming Conventions
- Use lowercase with hyphens:
my-element - Names must contain a hyphen (web component spec)
- Be descriptive:
product-cardnotpc - Use consistent prefixes for related elements:
form-input,form-select,form-button
Related Skills
- javascript-author - Write vanilla JavaScript for Web Components with function...
- data-attributes - Using data-* attributes as the HTML/CSS/JS bridge for sta...
- state-management - Client-side state patterns for Web Components
- accessibility-checker - Ensure WCAG2AA accessibility compliance