Home › Lit / web components › Lit web components rules

Lit web components rules

Cursor rules for Lit 3 web components in TypeScript: reactive properties, templates, styles, events, and accessibility.

CursorLit / web components

How to use

Save this as .cursor/rules/lit.mdc in your repository root, commit it, and your agent will pick it up automatically. Edit the commands to match your project.

Note: Review and test before use. Provided as is, without warranty. See Terms.

.cursor/rules/lit.mdcDownload  
---
description: Lit web components conventions
globs: ["src/**/*.ts"]
alwaysApply: false
---

# Lit 3 web components

- One element per file: `@customElement('rs-button') export class RsButton extends LitElement`. Tag names use the project prefix and a hyphen. Add `declare global { interface HTMLElementTagNameMap { 'rs-button': RsButton } }`.
- Public API via `@property()` (with `type` and `reflect: true` only when styling needs the attribute); internal state via `@state()`. Boolean attributes default to `false`.
- Don't mutate objects/arrays in place; assign a new value so Lit sees the change.
- Templates use the `html` tagged template; bind events with `@click=${this.handleClick}`, properties with `.value=${...}`, booleans with `?disabled=${...}`. Use `repeat()` with a key for lists and `nothing` for empty output.
- Never insert untrusted HTML with `unsafeHTML`.
- Styles go in `static styles` using the `css` tagged template; expose theming via CSS custom properties (`--rs-button-bg`) and `::part()`; don't depend on global CSS.
- Communicate upward with `this.dispatchEvent(new CustomEvent('rs-change', { detail, bubbles: true, composed: true }))`. Document events and properties in JSDoc (for the custom elements manifest).
- Lifecycle: `connectedCallback`/`disconnectedCallback` (always call `super`) for global listeners; `willUpdate` for derived state; `updated` for post-render DOM work. Reuse logic with reactive controllers.
- Forms: form-associated elements with `static formAssociated = true` and `ElementInternals` when the component is an input.
- Accessibility: semantic elements inside the shadow root, `delegatesFocus` for focusable wrappers, labels passed through.

## Done when
Typecheck, lint, and `@web/test-runner` (or Vitest browser mode) tests pass.

More: all Lit / web components rules · all Cursor rules

Related rules

Astro content site rules

Cursor rules for Astro 5 sites with content collections, islands, and zero-JS-by-default pages.

CursorAstro

Chrome extension (Manifest V3) rules

Cursor rules for building Manifest V3 browser extensions with TypeScript and minimal permissions.

CursorChrome extensions

Next.js 16 rules (Cache Components, proxy.ts)

Cursor rules for Next.js 16 App Router: Cache Components with "use cache", proxy.ts, async request APIs, Turbopack.

CursorNext.js

Next.js App Router (TypeScript) rules

Cursor project rules for Next.js 15 App Router apps with TypeScript, Server Components, and Tailwind.

CursorNext.js

Nuxt 3 + Vue rules

Cursor rules for Nuxt 3 / Vue 3 apps using the Composition API, script setup and Pinia.

CursorVue / Nuxt

Qwik + Qwik City rules

Cursor rules for Qwik and Qwik City apps: resumability, $ boundaries, signals, routeLoader$ and routeAction$.

CursorQwik

Get new rules weekly

One email a week: fresh rule files, agent tips, and what's changing in Cursor, Claude Code and Copilot. Free, unsubscribe anytime.

Opens the Rulestack Newsletter on beehiiv in a new tab. Or subscribe directly on beehiiv.