npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@intescia/ts-plugin-lit-binding-checker

v1.9.2

Published

TypeScript Language Service plugin: checks Lit templates .prop bindings & static attributes against child components (scopedElements).

Readme

ts-plugin-lit-binding-checker

A TypeScript Language Service plugin that provides type checking for Lit element templates. It validates property bindings, event handlers, attributes, and slots against your web component definitions.

Features

  • Property binding validation — Type-check .prop=${value} bindings against component properties
  • Event handler validation — Verify @event=${handler} matches the CustomEvent<T> type dispatched by the component
  • Attribute validation — Check static attributes against component properties
  • Slot validation — Ensure slot="name" attributes reference declared slots (@slot JSDoc)
  • Go to definition — Ctrl+Click on properties and events to jump to their definitions
  • Hover information — See property types and event signatures on hover
  • CLI tool — Run checks in CI/CD pipelines

Supported Patterns

Scoped Element Registries

Works with both scoped registry implementations:

Open-WC (@open-wc/scoped-elements)

import { ScopedElementsMixin } from '@open-wc/scoped-elements/lit-element.js';

class MyComponent extends ScopedElementsMixin(LitElement) {
  static scopedElements = {
    'child-element': ChildElement,
  };
  // or as a getter
  static get scopedElements() {
    return { 'child-element': ChildElement };
  }
}

Lit Labs (@lit-labs/scoped-registry-mixin)

import { ScopedRegistryHost } from '@lit-labs/scoped-registry-mixin';

class MyComponent extends ScopedRegistryHost(LitElement) {
  static elementDefinitions = {
    'child-element': ChildElement,
  };
}

Event Detection

The plugin automatically detects events from your TypeScript code:

Automatic detection from new CustomEvent()

class MyInput extends LitElement {
  private onChange() {
    // Plugin detects the event name and infers the detail type
    this.dispatchEvent(new CustomEvent('value-changed', {
      detail: { value: this.value }
    }));
  }
}

Explicit type annotation

this.dispatchEvent(new CustomEvent<{ value: string }>('value-changed', {
  detail: { value: this.value }
}));

JSDoc @fires tag (useful for .d.ts files or documentation)

/**
 * @fires value-changed - Emitted when value changes with `{ value: string }`.
 * @fires selection-changed - Emitted with `{ items: Item[] }`.
 */
class MyInput extends LitElement { ... }

Note: For components distributed as .d.ts declaration files, only JSDoc @fires tags are available since the source code is not present.

Slot Documentation

Document slots with the @slot JSDoc tag:

/**
 * @slot (default) - Default slot for main content.
 * @slot header - Slot for header content.
 * @slot footer - Slot for footer content.
 */
class MyCard extends LitElement {
  render() {
    return html`
      <slot name="header"></slot>
      <slot></slot>
      <slot name="footer"></slot>
    `;
  }
}

## Installation

```bash
npm install -D @intescia/ts-plugin-lit-binding-checker

Configuration

Add the plugin to your tsconfig.json:

{
  "compilerOptions": {
    "plugins": [
      {
        "name": "@intescia/ts-plugin-lit-binding-checker",
        "ignoreUndefined": true,
        "ignoreAttribute": false,
        "ignoreFiles": ["**/*.test.ts", "**/*.spec.ts"]
      }
    ]
  }
}

Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | ignoreUndefined | boolean | false | Ignore type mismatches caused only by \| undefined | | ignoreAttribute | boolean | false | Disable attribute validation (keep only .prop checks) | | ignoreFiles | string[] | [] | Glob patterns for files to exclude from checking | | debugCache | boolean | false | Log cache diagnostics to tsserver log |

VS Code Setup

To use the plugin in VS Code, configure the workspace to use the local TypeScript version:

  1. Create or edit .vscode/settings.json:
{
  "typescript.tsdk": "node_modules/typescript/lib",
  "typescript.enablePromptUseWorkspaceTsdk": true
}
  1. Open a TypeScript file and click on the TypeScript version in the status bar
  2. Select "Use Workspace Version"

CLI Usage

Run type checking from the command line or in CI:

# Basic usage
npx lit-binding-check tsconfig.json

# With options
npx lit-binding-check tsconfig.json --ignore-undefined --ignore-attribute

# Ignore specific files
npx lit-binding-check tsconfig.json --ignore-files "**/*.test.ts" "**/*.spec.ts"

Exit Codes

  • 0 — No errors found
  • 1 — Type errors detected

Error Codes

| Code | Description | |------|-------------| | 90010 | Custom element tag not found in scopedElements/elementDefinitions | | 90011 | Property not found on the component class | | 90012 | Property type mismatch | | 90020 | Attribute on unresolved element (warning) | | 90021 | Unknown attribute on component (warning) | | 90022 | Attribute value type mismatch | | 90030 | Event handler type mismatch | | 90031 | Event detail type mismatch (JSDoc-based) | | 90032 | Event not declared on component (warning) | | 90040 | Named slot not declared on component (warning) | | 90041 | Default slot content but no default slot declared (warning) |

Examples

Property Binding Error

class MyPage extends ScopedElementsMixin(LitElement) {
  static scopedElements = {
    'user-card': UserCard,
  };

  render() {
    return html`
      <user-card
        .userId=${123}        <!-- ✓ OK if userId: number -->
        .userName=${"Alice"}  <!-- ✗ Error if userName: number -->
      ></user-card>
    `;
  }
}

Event Handler Error

// UserCard dispatches: CustomEvent<{ id: string }>
// But handler expects: CustomEvent<{ id: number }>

render() {
  return html`
    <user-card
      @user-selected=${(e: CustomEvent<{ id: number }>) => {
        // ✗ Error: event detail type mismatch
        console.log(e.detail.id);
      }}
    ></user-card>
  `;
}

Slot Error

// MyCard only declares: @slot header, @slot footer

render() {
  return html`
    <my-card>
      <div slot="header">OK</div>
      <div slot="sidebar">✗ Error: slot "sidebar" not declared</div>
    </my-card>
  `;
}

License

MIT