ui-convert-extractor-web-components
Installation
SKILL.md
Web Components Extractor
Converts Web Components (Lit elements, vanilla custom elements) into Design IR.
What This Extracts
| Source Pattern | IR Output |
|---|---|
html\...`` (Lit template) |
Node tree |
<slot> |
Content placeholder |
CSS in static styles |
Token mapping |
customElements.define('my-el', ...) |
Component |
| Shadow DOM structure | Node hierarchy |
Lit Extraction
Component Structure
import { LitElement, html, css } from 'lit';
import { customElement, property } from 'lit/decorators.js';
@customElement('my-button')
class MyButton extends LitElement {
static styles = css`
:host {
display: inline-flex;
}
button {
background: var(--primary, #6366f1);
color: white;
padding: 8px 16px;
border-radius: 6px;
border: none;
font-family: 'Inter', sans-serif;
font-size: 14px;
cursor: pointer;
}
`;
@property() label = 'Click me';
@property() variant = 'primary';
render() {
return html`
<button class="${this.variant}">
<slot>${this.label}</slot>
</button>
`;
}
}
Extraction Steps
- Parse
render()method → extract thehtmltagged template literal - Parse
static styles→ extract thecsstagged template literal - Map properties → understand component interface (props = potential overrides)
- Handle
<slot>→ mark as content placeholder in IR - Resolve CSS custom properties → map
var(--name)to tokens
Lit-Specific Patterns
| Pattern | Extraction Rule |
|---|---|
html\...`` |
Parse as HTML template |
css\...`` |
Parse as CSS |
${this.prop} |
Text placeholder |
?attr=${bool} |
Ignore boolean binding |
.prop=${val} |
Ignore property binding |
@event=${handler} |
Ignore event binding |
<slot> |
Content placeholder |
<slot name="header"> |
Named placeholder |
${repeat(items, ...)} |
One iteration |
${when(cond, ...)} |
Truthy branch |
Vanilla Custom Elements
class MyCard extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: 'open' });
shadow.innerHTML = `
<style>
.card { border: 1px solid #e2e8f0; border-radius: 8px; padding: 16px; }
.card-title { font-size: 18px; font-weight: 600; }
</style>
<div class="card">
<h2 class="card-title"><slot name="title"></slot></h2>
<div class="card-body"><slot></slot></div>
</div>
`;
}
}
customElements.define('my-card', MyCard);
Extract from shadow.innerHTML or this.shadowRoot.innerHTML. Parse embedded HTML and CSS.
Shadow DOM Considerations
- Styles in shadow DOM are scoped — extract them per-component
:hostselector → maps to the component's own styles::slotted()selector → styles for slotted content (note but don't extract)- CSS custom properties (declared with
--) → cross shadow boundary, map to tokens
Cross-references
- IR format →
ui-convert-ir-schema - Token lookup →
tokens.jsonfromui-convert-token-miner - Called by →
ui-convert-coordinator(whentech: "lit"or"web-components")
Related skills