Documentation

Commands

Generate

  • Generates CEM files from source code using syntax analysis powered by go and tree-sitter .
  • Identifies custom elements, classes, variables, functions, and exports.
  • Supports elements written in idiomatic style using Lit and TypeScript, with a @customElement decorator, and @property decorators on class fields.
cem generate best supports LitElements written in idiomatic style with TypeScript decorators. There is rudimentary support for extends HTMLElement, but it is not a high priority for development. If you need something more specific open an issue .

JSDoc

Use JSDoc comments to add metadata to your element classes, similar to other tools. Add a description by separating the name of the item with -

  • @attr / @attribute — Custom element attributes
  • @csspart — CSS shadow parts. See Slots and Parts
  • @cssprop / @cssproperty — Custom CSS properties
  • @cssstate — Custom CSS states
  • @demo — Demo URL
  • @deprecated — Marks a feature or member as deprecated
  • @event — Custom events dispatched by the element
  • @slot — Named or default slots. See Slots and Parts
  • @summary — Short summary for documentation

See the generate test fixtures directory for examples

Slots and Parts

cem automatically detects <slot> elements and part attributes in your element’s render() template, merging them with any information provided via JSDoc. You can also document slots and parts inline in your template HTML using HTML comments. This helps in documenting them for your users, but is not required to detect them.

  • If the comment is a plain string, it will be used as the description for the element. In cases where an element is both a slot and a part, the description will only be applied to the slot.
  • For more detailed documentation, you can use YAML inside the comment.
  • Markdown is supported in all HTML comment documentation. Use a backslash (\) to escape backticks.

Examples

Plain String Comment

A simple comment will be treated as the description. Markdown content is supported and encouraged.

<!-- This is the **default** `slot`. -->
<slot></slot>

YAML Comment

For more complex metadata, use YAML syntax.

<!--
  summary: The main slot for content
  description: |
    This slot displays user-provided content.
    Supports multiline **markdown**.
    e.g. `code`
  deprecated: true
-->
<slot></slot>

Documenting Slots and Parts together

When an element is both a slot and a part, you can document both in a single comment.

<!-- slot:
       summary: The `info` slot
     part:
       summary: The `info-part` part
-->
<slot name="info" part="info-part"></slot>
When including inline markdown `code` in your comments in lit-html templates, you will need to escape the backticks in the comment.

CSS Custom Properties

Supports CSS Custom Properties by scanning css files and css tagged-template-literals. cem also discovers properties defined in :host rules.

  • Custom properties beginning with _ will be ignored (treated as “private”) e.g. var(--_private)
  • If you provide a Design Tokens Community Group format module (JSON) to cem via the --design-tokens flag, cem will add metadata from your design system to any matching css variables it finds in your elements
  • You can use jsdoc-like comment syntax before each var call to document your variables

Example

:host {
  /**
   * A property defined on the host
   * @summary The host's custom property
   */
  --host-property: red;

  color:
    /**
     * custom color for use in this element
     * @summary color
     * @deprecated just use the `color` property
     */
    var(--custom-color);
  border:
    1px
    solid
    /** Border color of the element */
    var(--border-color);
}

When you have a declaration where the LHS and RHS both contain CSS custom properties, you have to position your comments so that they target the correct variable:

Good:

/** comment for --a */
color: var(--a);
/** comment for --b */
--b: blue;
/** comment for --c */
--c:
  /** comment for --d */
  var(--d);

Bad:

/** comment for --d */
--c: var(--d);

Demos

cem generate supports documenting your elements’ demos by linking directly from JSDoc, or by configurable file-system based discovery.

JSDoc @demo Tag

Add demos directly to your element class or members with the @demo tag:

/**
 * @demo https://example.com/my-element-plain/
 * @demo https://example.com/my-element-fancy/ - A fancier demo with description
 */
@customElement('my-element')
class MyElement extends LitElement {
  // ...
}

Demos defined this way will always appear in your manifest for the element.

Automatic Demo Discovery

cem can automatically discover demos from your codebase based on your repository structure and configuration. Demos that are co-located with their component’s source module will be prioritized in the generated manifest.

Demo Discovery

The urlPattern uses the standard URLPattern syntax with named parameters (:paramName). You can use it to match file paths and extract parameters to build your demo URLs.

For example, if your demos are in subdirectories like src/my-element/demos/foo.html, you could use a pattern like this:

sourceControlRootUrl: "https://github.com/your/repo/tree/main/"
generate:
  demoDiscovery:
    fileGlob: "src/**/demos/*.html"
    urlPattern: "/src/:tag/demos/:demo.html"
    urlTemplate: "https://example.com/elements/{{.tag | alias}}/{{.demo | slug}}/"

URL Template Functions

The urlTemplate supports Go template syntax with built-in functions:

  • alias - Apply element alias mapping
  • slug - Convert to URL-friendly format
  • lower - Convert to lowercase
  • upper - Convert to uppercase

Use pipeline syntax ({{.param | function}}) or function calls ({{function .param}}).

Demo discovery options:

OptionTypeDescription
fileGlobstringGlob pattern for discovering demo files.
sourceControlRootUrlstringCanonical public source control URL for your repository root (on the main branch).
urlPatternstringURLPattern with named parameters (:param) for matching demo file paths.
urlTemplatestringGo template with functions for generating canonical demo URLs.

Monorepos

If you are planning to use cem in an npm or yarn monorepo, the best way for now is to create a new .config/cem.yaml file for each package you want to generate for, instead of using a top-level config file.

Example

Root package.json:

{
  "scripts": {
    "generate": "npm run generate --workspaces"
  },
  "workspaces": [
    "./core",
    "./elements"
  ]
}

core/.config/cem.yaml:

generate:
  files:
    - './**/*.ts'

core/package.json

{
  "scripts": {
    "generate": "cem generate"
  }
}

elements/.config/cem.yaml:

generate:
  files:
    - './**/*.ts'

elements/package.json

{
  "scripts": {
    "generate": "cem generate"
  }
}

Usage

Generate a custom elements manifest from your files:

cem generate \
  "src/**/*.ts" \
  --design-tokens npm:@my-ds/tokens/tokens.json \
  --exclude "src/**/*.test.ts" \
  --output custom-elements.json

For npm projects you can use npx @pwrs/cem generate ....

The generate command does not support remote packages. To inspect a remote package’s manifest, use the cem list command.

Arguments

ArgumentTypeDescription
<files or globs>positional (array)Files or glob patterns to include
--package, -pstringPath to a package directory.
--output, -ostringWrite the manifest to this file instead of stdout
--watch, -wboolWatch files for changes and regenerate automatically
--exclude, -earrayFiles or glob patterns to exclude
--no-default-excludesboolDo not exclude files by default (e.g., .d.ts files will be included unless excluded explicitly)
--design-tokensstringPath or npm specifier for DTCG-format design tokens
--design-tokens-prefixstringCSS custom property prefix for design tokens
--demo-discovery-file-globstringGlob pattern for discovering demo files
--demo-discovery-url-patternstringURLPattern with named parameters for matching demo file paths
--demo-discovery-url-templatestringGo template with functions for generating canonical demo URLs
--source-control-root-urlstringGlob pattern for discovering demo files
--project-dirstringDeprecated: Use --package instead.

By default, some files (like .d.ts TypeScript declaration files) are excluded from the manifest. Use --no-default-excludes if you want to include all matching files and manage excludes yourself.