Skip to content

This package generates types for JSX environments for custom elements / web components

License

Notifications You must be signed in to change notification settings

wc-toolkit/jsx-types

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

62 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

workbench with tools, html, css, javascript, and jsx logos

WC Toolkit Custom Element JSX Types Generator

This package is designed to generate JSX types for your custom elements. These types will generate inline documentation, autocomplete, and type-safe validation for your custom elements in frameworks that use JSX like React (19+), Preact, StencilJS, and SolidJS.

demo of autocomplete features for custom elements in a jsx project

This allows developers to use your custom elements in their JSX projects with full type support, making it easier to integrate and use your components.

NOTE: If you are using react 18 or below, check out our react wrappers.

Types will be generated for all custom elements defined in your Custom Elements Manifest.

This includes types and documentation for:

  • Custom elements (types and docs)
  • Attributes (types and docs)
  • Properties (types and docs)
  • Events (types and docs)
  • Methods (types and docs)
  • Slots (docs)
  • CSS Custom Properties (docs)
  • CSS States (docs)

Usage

This package includes two ways to generate the custom data config file:

  1. programatically calling a function in your build pipeline
  2. as a plugin for the Custom Element Manifest Analyzer

Install

npm i -D @wc-toolkit/jsx-types

Build Pipeline

import { generateJsxTypes, JsxTypesOptions } from "@wc-toolkit/jsx-types";
import manifest from "./path/to/custom-elements.json";

const options: JsxTypesOptions = {...};

generateJsxTypes(manifest, options);

CEM Analyzer

Set-up

Ensure the following steps have been taken in your component library prior to using this plugin:

Import

// custom-elements-manifest.config.js

import { jsxTypesPlugin } from "@wc-toolkit/jsx-types";

const options = {...};

export default {
  plugins: [
    jsxTypesPlugin(options)
  ],
};

Implementation

In order for teams to take advantage of this, all they need to do is import the types in their project. There are two ways to configure the JSX types:

Option 1: TSConfig Configuration

Add the types to your tsconfig.json:

{
  "compilerOptions": {
    "types": ["path/to/jsx-types"]
  }
}

Option 2: TypeScript Declaration File

Create a declaration file and extend JSX's IntrinsicElements:

// custom-elements-types.d.ts
import type { CustomElements, CustomCssProperties } from "path/to/jsx-types";

declare module "my-library" {
  namespace JSX {
    interface IntrinsicElements extends CustomElements {}
  }
  export interface CSSProperties extends CustomCssProperties {}
}

NOTE: Libraries will have their own module names you will need to use when extending the IntrinsicElements interface. For example, Preact requires you to use the "preact" module name instead of "my-library" (declare module "preact") and StencilJS uses "@stencil/core" (declare module "@stencil/core").

Configuration Options

The JsxTypesOptions interface provides several configuration options to customize how types are generated for your project:

Basic Options

fileName

  • Type: string
  • Default: "custom-element-jsx.d.ts"
  • Description: The name of the generated type definition file.
{
  fileName: "my-components.d.ts"
}

outdir

  • Type: string
  • Default: "./"
  • Description: The output directory where the generated types file will be saved.
{
  outdir: "./types"
}

exclude

  • Type: string[]
  • Default: []
  • Description: Array of component names to exclude from type generation.
{
  exclude: ["my-internal-component", "my-deprecated-component"]
}

Import Configuration

componentTypePath

  • Type: (name: string, tag?: string, modulePath?: string) => string
  • Description: A function that returns the import path for each component. This is useful when you need to customize the import statements in the generated types.
{
  componentTypePath: (name, tagName) => 
    `my-lib/components/${tagName}/${tagName}.js`
}

globalTypePath

  • Type: string
  • Description: When provided, generates a single import statement for all components from this path instead of individual imports. This is useful if your library has a barrel file that exports all components.
{
  globalTypePath: "my-lib"
}

defaultExport

  • Type: boolean
  • Default: false
  • Description: Set to true if your component classes use default exports instead of named exports.
{
  defaultExport: true
}

Event Configuration

stronglyTypedEvents

  • Type: boolean
  • Default: false
  • Description: This feature is highly recommended for better type safety and autocomplete. Creates event types where the event's target is strongly typed to the custom element, providing better autocomplete and type safety for event handlers. When enabled, e.detail and e.target are strongly typed.
{
  stronglyTypedEvents: true
}

includeDefaultDOMEvents

  • Type: boolean
  • Default: false
  • Description: Includes standard DOM events (e.g., onClick, onHover, etc.) in the generated types. The down side is that it can pollute the component API with attributes that aren't relevant to the component.
{
  includeDefaultDOMEvents: true
}

globalEvents

  • Type: string
  • Description: TypeScript type reference for global event props to add to all component types. This can be useful for adding custom events or event handlers to all components for things like custom telemetry.
{
  globalEvents: "React.DOMAttributes<HTMLElement>"
}

Additional Options

allowUnknownProps

  • Type: boolean
  • Default: false
  • Description: Allows users to add undefined attributes or props to the custom elements without TypeScript errors.
{
  allowUnknownProps: true
}

excludeCssCustomProperties

  • Type: boolean
  • Default: false
  • Description: Excludes CSS custom property types from generation.
{
  excludeCssCustomProperties: true
}

tagFormatter

  • Type: (tagName: string) => string
  • Description: Optional function to format tag names before processing. Useful for adding prefixes, suffixes, or transforming tag names.
{
  tagFormatter: (tagName) => tagName.replace("my-", "custom-")
}

Utility Options

skip

  • Type: boolean
  • Default: false
  • Description: Skips the entire type generation process when set to true.
{
  skip: process.env.SKIP_TYPES === "true"
}

debug

  • Type: boolean
  • Default: false
  • Description: Enables debug logging to help troubleshoot type generation issues.
{
  debug: true
}

Deprecated Options

prefix (deprecated)

  • Type: string
  • Description: Use tagFormatter instead. Adds a prefix to tag references.

suffix (deprecated)

  • Type: string
  • Description: Use tagFormatter instead. Adds a suffix to tag references.

overrideCustomEventType (deprecated)

  • Type: boolean
  • Default: false
  • Description: This feature never worked as intended and will be removed in the next major version.

Framework-Specific Considerations

SolidJS

When using these generated types with SolidJS, there are several important considerations to ensure proper integration:

Custom TypeScript Declaration File

If you are using a custom TypeScript declaration file, SolidJS has a custom type to include the attribute prefixes, so you will need to use CustomElementsSolidJs instead of CustomElements. For example:

// custom-elements-types.d.ts
import type { CustomElementsSolidJs, CustomCssProperties } from "path/to/jsx-types";

declare module "my-library" {
  namespace JSX {
    interface IntrinsicElements extends CustomElementsSolidJs {}
  }
  export interface CSSProperties extends CustomCssProperties {}
}

Property Binding

SolidJS generates special type definitions that include property prefixes to handle different binding scenarios:

  • attr:propertyName - For attribute binding (string values)
  • prop:propertyName - For property binding (any type)
  • bool:propertyName - For boolean properties

This allows SolidJS to properly handle web component properties:

// Attribute binding (as string)
<my-component attr:value={someString} />

// Property binding (with signals or objects)
<my-component prop:value={someSignal()} />

// Boolean property
<my-component bool:disabled={isDisabled} />

Custom Events

SolidJS uses the on: prefix for custom events. The generated types include proper event handler types:

import { createSignal } from 'solid-js';

const [value, setValue] = createSignal('');

<my-input
  prop:value={value()}
  on:my-input={(e) => {
    // e.target is strongly typed when stronglyTypedEvents is enabled
    setValue(e.target.value);
  }}
  on:my-change={(e) => {
    // e.detail is strongly typed when stronglyTypedEvents is enabled
    console.log('Changed:', e.detail);
  }}
/>

Recommended Configuration for SolidJS

When generating types for SolidJS projects, use the following configuration:

generateJsxTypes(manifest, {
  outdir: "./types",
  fileName: "custom-element-jsx.d.ts",
  defaultExport: true, // if your components use default exports
  stronglyTypedEvents: true, // for better event type safety
  componentTypePath: (name, tagName) => 
    `your-lib/components/${tagName}/${tagName}.js`
});

TypeScript Declaration

For SolidJS, create a declaration file that extends the solid-js JSX namespace:

// custom-elements-types.d.ts
import type { CustomElements, CustomCssProperties } from "./path/to/types/custom-element-jsx";

declare module "solid-js" {
  namespace JSX {
    interface IntrinsicElements extends CustomElements {}
  }
}

// Optional: Extend CSS properties
declare module "csstype" {
  interface Properties extends CustomCssProperties {}
}

innerHTML and textContent

SolidJS types also include innerHTML and textContent properties for setting element content:

<my-component innerHTML="<strong>Bold text</strong>" />
<my-component textContent="Plain text content" />

Reactive Property Updates

When working with reactive values in SolidJS, always use the prop: prefix for non-string properties:

import { createSignal } from 'solid-js';

const [isOpen, setIsOpen] = createSignal(false);
const [items, setItems] = createSignal([]);

<my-dialog prop:open={isOpen()} />
<my-list prop:items={items()} />

Refs and Methods

Access custom element methods using SolidJS refs:

import { onMount } from 'solid-js';

let dialogRef: any;

onMount(() => {
  // Call custom element methods
  dialogRef?.show();
});

<my-dialog ref={dialogRef}>
  Dialog content
</my-dialog>

React

For React 19+ projects, the types work with the native custom element support:

<my-component
  value="hello"
  disabled={false}
  onmy-event={(e) => console.log(e)}
/>

Preact

Preact requires extending the "preact" module:

declare module "preact" {
  namespace JSX {
    interface IntrinsicElements extends CustomElements {}
  }
}

StencilJS

StencilJS requires extending the "@stencil/core" module:

declare module "@stencil/core" {
  namespace JSX {
    interface IntrinsicElements extends CustomElements {}
  }
}

Complete Configuration Example

Here's a comprehensive example showing all commonly used options:

import { generateJsxTypes } from "@wc-toolkit/jsx-types";
import manifest from "./custom-elements.json";

generateJsxTypes(manifest, {
  // Output configuration
  fileName: "custom-element-jsx.d.ts",
  outdir: "./types",
  
  // Component filtering
  exclude: ["internal-component"],
  
  // Import configuration
  componentTypePath: (name, tagName, modulePath) => {
    return `my-library/components/${tagName}/${tagName}.js`;
  },
  defaultExport: true,
  
  // Event configuration
  stronglyTypedEvents: true,
  includeDefaultDOMEvents: true,
  
  // Tag formatting
  tagFormatter: (tagName) => tagName.toLowerCase(),
  
  // Additional features
  allowUnknownProps: false,
  excludeCssCustomProperties: false,
  
  // Development
  debug: process.env.DEBUG === "true",
  skip: false,
});

For more information about this library and other Web Component tools, check out the WC Toolkit website.

About

This package generates types for JSX environments for custom elements / web components

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •