--- name: lit description: Web Components development with Lit including custom elements, reactive properties, shadow DOM, and interoperability. allowed-tools: Read, Write, Edit, Bash, Glob, Grep --- # Lit Skill Expert assistance for building Web Components with Lit. ## Capabilities - Create Lit elements with reactive properties - Implement shadow DOM styling - Handle events and lifecycle callbacks - Build composable component libraries - Ensure framework interoperability - Configure SSR with Lit ## Usage Invoke this skill when you need to: - Build framework-agnostic components - Create design system primitives - Implement custom elements - Ensure cross-framework compatibility - Build micro-frontends ## Inputs | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | elementName | string | Yes | Custom element name (must have hyphen) | | properties | array | No | Reactive properties | | shadowDom | boolean | No | Use shadow DOM (default: true) | | typescript | boolean | No | Use TypeScript (default: true) | ## Component Patterns ### Basic Lit Element ```typescript // src/components/user-card.ts import { LitElement, html, css } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; interface User { id: string; name: string; email: string; avatar?: string; } @customElement('user-card') export class UserCard extends LitElement { static styles = css` :host { display: block; padding: 1rem; border: 1px solid #e5e7eb; border-radius: 0.5rem; } .user-card { display: flex; gap: 1rem; } .avatar { width: 64px; height: 64px; border-radius: 50%; overflow: hidden; background: #e5e7eb; display: flex; align-items: center; justify-content: center; } .avatar img { width: 100%; height: 100%; object-fit: cover; } .initials { font-weight: bold; font-size: 1.25rem; } button { padding: 0.5rem 1rem; border: none; border-radius: 0.25rem; cursor: pointer; } button.primary { background: #3b82f6; color: white; } `; @property({ type: Object }) user!: User; @property({ type: Boolean }) editable = false; @state() private isEditing = false; @state() private editedName = ''; private get initials() { return this.user.name .split(' ') .map(n => n[0]) .join('') .toUpperCase(); } private startEditing() { this.editedName = this.user.name; this.isEditing = true; } private save() { this.dispatchEvent(new CustomEvent('user-updated', { detail: { ...this.user, name: this.editedName }, bubbles: true, composed: true, })); this.isEditing = false; } private cancel() { this.isEditing = false; } render() { return html`
${this.user.email}
${this.editable ? html`` : null} `}Loading...
`; } if (this.usersController.error) { return html`Error: ${this.usersController.error.message}
`; } return html`${highlight(text, searchQuery)}
` ``` ### Slots and Composition ```typescript @customElement('modal-dialog') export class ModalDialog extends LitElement { static styles = css` :host { display: none; } :host([open]) { display: block; } .backdrop { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; } .dialog { background: white; padding: 1.5rem; border-radius: 0.5rem; max-width: 500px; width: 100%; } `; @property({ type: Boolean, reflect: true }) open = false; private handleBackdropClick(e: Event) { if (e.target === e.currentTarget) { this.dispatchEvent(new CustomEvent('close')); } } render() { return html`Are you sure you want to proceed?