# Publish a Custom Elements Manifest

> Write custom-elements.json from your Lit components with the manifest option or the lit-devtools manifest command, for editors, Storybook and the people who install your package.

[New in v0.24.0](/reference/changelog/version/0-24-0/ "See the 0.24.0 release notes")

Ship a `custom-elements.json` that documents your components, written from the same source reading the DevTools panel uses. Skip this page if you already generate one with the analyzer and are happy with it; [Manifest generators compared](/overview/compare-manifest/) sets the tools side by side.

A Custom Elements Manifest is a JSON file that lists each element’s tag, properties, attributes, events, slots, parts and CSS properties. Editors, Storybook and documentation sites read it, and a package points at it with the `customElements` field in its `package.json`.

## Turn it on

Set `manifest: true`. `vite build` then emits `custom-elements.json` beside the bundle, and the dev server serves it at `/custom-elements.json`.

```ts
import {defineConfig} from 'vite';
import {litPlugin} from '@oddsquad/lit-devtools/vite';

export default defineConfig({
  plugins: [litPlugin({manifest: true})],
});
```

The build reads every module of the bundle, so its manifest covers each component the bundle contains. Each module path names the built file that holds the component, such as `dist/my-lib.js`, because that is what a consumer imports. The dev server reads every script under `src` when it starts and follows each change on disk, so its manifest lists your components before any page loads them. Set `scan` to the folders your components live in, or to `false` to list only what pages load. It links the manifest in each page’s head, so the browser extension shows the docs too.

## Write what the manifest reads

Document a component with JSDoc on the class and its fields:

```ts
import {LitElement, html} from 'lit';
import {customElement, property} from 'lit/decorators.js';

/**
 * A button that submits the form it sits in.
 *
 * @summary The form's submit button.
 * @fires submit-start - Before the form is sent.
 * @slot - The label.
 * @csspart base - The native button.
 * @cssprop [--x-button-gap=4px] - Space between icon and label.
 */
@customElement('x-button')
export class XButton extends LitElement {
  /** How much room the button takes. */
  @property({reflect: true}) size: 'small' | 'large' = 'small';

  render() {
    return html`<button part="base"><slot></slot></button>`;
  }
}
```

The class comment gives the description and each tagged entry. A field’s comment gives its description, its type annotation the type, and its initializer the default. `@property()` names the attribute it maps to, and `reflect: true` marks it `reflects`. `@state()` and private members stay out. The [components guide](/guides/devtools/components/#your-own-components) lists every tag the reader understands.

Public methods are listed too, with their parameters and return type. Types come from the annotations, or from `@param {Type} name - description` and `@returns {Type} description` in plain JavaScript. Lifecycle callbacks such as `render()`, `updated()` and `connectedCallback()` are how Lit calls your class, so they stay out.

A class lists the members it inherits from your own base classes and mixins, each marked `inheritedFrom`, so tools need no inheritance walk. Types are the text you wrote; nothing is inferred from the checker.

## Keep a copy in your package

Add `write` to keep the file in your project as well. The dev server rewrites it as you edit, and `vite build` rewrites it from every module of the bundle.

```ts
import {defineConfig} from 'vite';
import {litPlugin} from '@oddsquad/lit-devtools/vite';

export default defineConfig({
  plugins: [litPlugin({manifest: {write: true}})],
});
```

When your `package.json` has no `customElements` field yet, the plugin sets it to the file it wrote. A field you already set is left alone.

## Write it from the command line

`lit-devtools manifest` reads every script under `src`, not only the ones a build reached, and writes `custom-elements.json`. Run it before you publish:

```json
{
  "scripts": {
    "prepublishOnly": "lit-devtools manifest"
  }
}
```

It resolves imports through your Vite config, so aliases work; without one, through `tsconfig.json` paths and package `exports`. The [CLI reference](/reference/cli/#lit-devtools-manifest) lists its flags.

## Related

[Options: manifest](/reference/options/#manifest)Each output, its default and how to name its file.

[Inspect components](/guides/devtools/components/)Read the same docs in the DevTools panel.
