wc-dox
v1.3.5
Published
A web component API documentation generator
Maintainers
Readme
Web Component Documentation (wc-dox)
The wc-dox package and it's components are designed to be a way to quickly and consistently document your custom element APIs using the Custom Elements Manifest.
If you're not already generating a Custom Elements Manifest, here is a list of options you can use to generate one.

Installation
npm i wc-doxYou can also use the package directly from a CDN:
<script type="module" src="https://cdn.jsdelivr.net/npm/wc-dox/cdn/index.js"></script>Prerequisites
This package requires a Custom Elements Manifest to function. If you don't have one yet, you'll need to generate it using one of these tools:
- @custom-elements-manifest/analyzer - The official analyzer
- CEM Analyzer Plugins - Extend the analyzer with additional functionality
Usage
After installing, you can load the documentation at the root of your project.
import { setWcDoxConfig } from 'wc-dox/index.js';
import manifest from './custom-elements.json' with { type: 'json' };
setWcDoxConfig(manifest);Now that it's loaded, you can load the appropriate documentation by passing the component's tag name or class name to the component.
<wc-dox tag="my-element"></wc-dox>
<!-- or -->
<wc-dox component-name="MyElement"></wc-dox>Note: You must specify either the
tagattribute or thecomponent-nameattribute for the component to work properly.
Framework Integration
React
If you're using React, you can import the React wrapper components:
import { WcDox } from 'wc-dox/react';
import manifest from './custom-elements.json' with { type: 'json' };
import { setWcDoxConfig } from 'wc-dox';
setWcDoxConfig(manifest);
function App() {
return <WcDox tag="my-element" />;
}The package includes React wrappers for all components: WcDox, WcCssParts, WcCssProps, WcCssStates, WcEvents, WcImports, WcMethods, WcProps, and WcSlots.
Component Attributes
All documentation components accept the following attributes:
tag (optional)
The tag name of the component to document. This should match the tag name defined in your custom elements manifest (typically from the @tag or @tagname JSDoc comment).
<wc-dox tag="my-element"></wc-dox>component-name (optional)
The JavaScript class name of the component to document. Use this when you don't have a tag name or prefer to reference by class name.
<wc-dox component-name="MyElement"></wc-dox>Important: You must provide either
tagorcomponent-namefor the component to display documentation.
Content is in the Light DOM
The content generated by these components is all render in the light DOM so that styles can be easily inherited from the rest of your application or so that customizations can easily be applied.
Flexible Implementation
The <wc-dox> element should be all that you need, but if you eed more flexibility, each of the sections can also be used independently as individual components.
<!-- CSS Parts docs -->
<wc-css-parts tag="my-element"></wc-css-parts>
<!-- CSS Custom Properties docs -->
<wc-css-props tag="my-element"></wc-css-props>
<!-- CSS Custom States docs -->
<wc-css-states tag="my-element"></wc-css-states>
<!-- Events docs -->
<wc-events tag="my-element"></wc-events>
<!-- Imports docs -->
<wc-imports tag="my-element"></wc-imports>
<!-- Methods docs -->
<wc-methods tag="my-element"></wc-methods>
<!-- Attributes and Properties docs -->
<wc-props tag="my-element"></wc-props>
<!-- Slots docs -->
<wc-slots tag="my-element"></wc-slots>Quick Reference
- Installation - How to install the package
- Prerequisites - Required dependencies
- Usage - Basic usage examples
- Framework Integration - Using with React and other frameworks
- Component Attributes - Available attributes
- Configuration - Customizing the output
- Styling - Applying custom styles
- Examples - Real-world usage examples
- Troubleshooting - Common issues and solutions
- TypeScript Support - Using with TypeScript
- API Reference - Complete configuration options
Configuration
The setWcDoxConfig function can take a second parameter to configure the documentation.
The <wc-dox> and <wc-imports> components have unique configurations, but the others follow a consistent API.
import { setWcDoxConfig, DoxConfig } from 'wc-dox/index.js';
import manifest from './custom-elements.json' with { type: 'json' };
const options: DoxConfig = {};
setWcDoxConfig(manifest, options);type DoxConfig = {
/** Hides a section of the documentation if it has no content */
hideOnEmpty?: boolean;
/** Configures the heading level for the API sections - default is 3 */
headingLevel?: 1 | 2 | 3 | 4 | 5 | 6;
/** Configures the CSS class for the API section headings */
headingClass?: string;
/** Configures the CSS class for the API section tables */
tableClass?: string;
/** Configures the `wc-dox` component contents */
dox?: DoxElementConfig;
/** Configures the `wc-imports` component contents */
imports?: ImportsElementConfig;
/** Configures the `wc-css-parts` component contents */
cssParts?: CssPartsElementConfig;
/** Configures the `wc-css-props` component contents */
cssProps?: CssPropsElementConfig;
/** Configures the `wc-css-states` component contents */
cssStates?: StatesElementConfig;
/** Configures the `wc-events` component contents */
events?: EventsElementConfig;
/** Configures the `wc-methods` component contents */
methods?: MethodsElementConfig;
/** Configures the `wc-props` component contents */
props?: PropsElementConfig;
/** Configures the `wc-slots` component contents */
slots?: SlotsElementConfig;
};Hide Empty Sections
By default, sections with no content are hidden. You can control this behavior with the hideOnEmpty option:
setWcDoxConfig(manifest, {
hideOnEmpty: false, // Show all sections even if empty
});Custom CSS Classes
You can apply custom CSS classes to the generated headings and tables:
setWcDoxConfig(manifest, {
headingClass: 'my-custom-heading',
tableClass: 'my-custom-table',
});Heading Level
The headingLevel setting controls the heading level for each of the sections of the API sections.
Dox Element Config
The <wc-dox> element works as a wrapper for the API components. The apiOrder setting controls the order in which the API sections are rendered. If you do not want a section to render at all, you can exclude it from the array.
type DoxElementConfig = {
/**
* Controls the order in which the API documentation sections are displayed
*
* Default value is ['imports', 'props', 'slots', 'methods', 'events', 'css-props', 'css-parts', 'css-states']
*/
apiOrder?: Array<
| 'imports'
| 'props'
| 'slots'
| 'methods'
| 'events'
| 'css-props'
| 'css-parts'
| 'css-states'
>;
};Imports Element Config
The imports element is a way for you to document the various ways to import your components. Each of the imports will be displayed in it's own tab.
type ImportsElementConfig = {
/** The heading for the imports section */
heading?: string;
/** The ID used for the skip-link */
headingId?: string;
/** The description for the imports section */
description?: string;
/** The copy button icon */
copyIcon?: string;
/** The copy button label */
copyLabel?: string;
/** The icon displayed when the content is copied */
copiedIcon?: string;
/** The label used when the content is copied */
copiedLabel?: string;
/** Sets the language class on `pre` tag instead of `code` tag */
langOnPreTag?: boolean;
/** The list of import options */
imports?: ImportConfig[];
};
type ImportConfig = {
/** The text displayed in the tab option */
label?: string;
/** The language the code - `html`, `js`, `ts`, etc. */
lang?: string;
/** An additional description that is specific to this import */
description?: string;
/**
* Use this function to specify import information for a given language. The tag and class names can be used to create dynamic component-specific import paths.
* @param tagName The tag name specified using the @tag or @tagName in the component's jsDoc
* @param className The JS class name for the component
* @returns string
*/
importTemplate?: (tagName: string, className: string) => string;
};Here's a sample configuration:
imports: {
heading: 'Imports',
headingId: 'imports',
description: 'You can import the component in the following ways:',
copyIcon:
'<?xml version="1.0" ?><svg style="enable-background:new 0 0 24 24;" version="1.1" viewBox="0 0 24 24" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g class="st0" id="grid_system"/><g id="_icons"><path d="M17,3h-6C8.8,3,7,4.8,7,7c-2.2,0-4,1.8-4,4v6c0,2.2,1.8,4,4,4h6c2.2,0,4-1.8,4-4c2.2,0,4-1.8,4-4V7C21,4.8,19.2,3,17,3z M15,17c0,1.1-0.9,2-2,2H7c-1.1,0-2-0.9-2-2v-6c0-1.1,0.9-2,2-2h1h5c1.1,0,2,0.9,2,2v5V17z M19,13c0,1.1-0.9,2-2,2v-4 c0-2.2-1.8-4-4-4H9c0-1.1,0.9-2,2-2h6c1.1,0,2,0.9,2,2V13z"/></g></svg>',
copyLabel: 'Copy import',
copiedIcon:
'<?xml version="1.0" ?><svg style="enable-background:new 0 0 36 36;" version="1.1" viewBox="0 0 36 36" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g id="Layer_1"/><g id="icons"><path class="st0" d="M12.8,28.7l-9.5-9.5c-0.4-0.4-0.4-1.1,0-1.6l1.5-1.5c0.4-0.4,1.1-0.4,1.6,0l7.2,7.2 l16-16c0.4-0.4,1.1-0.4,1.6,0l1.5,1.5c0.4,0.4,0.4,1.1,0,1.6L14.4,28.7C13.9,29.1,13.2,29.1,12.8,28.7z" id="check_x5F_mark_1_"/></g></svg>',
copiedLabel: 'Import copied',
imports: [
{
label: 'HTML',
lang: 'html',
importTemplate: (tagName, className) =>
`<script type="module" src="https://cdn.jsdelivr.net/npm/my-library/dist/${tagName}/${className}.js"><\/script>`,
},
{
label: 'NPM',
lang: 'js',
importTemplate: (tagName, className) =>
`import 'my-library/dist/${tagName}/${className}.js';`,
},
{
label: 'React',
lang: 'js',
importTemplate: tagName =>
`import 'my-library/react/${tagName}/index.js';`,
},
],
},Base Config
The other API blocks use the generic BaseElementConfig<T> type and follow a consistent pattern for documenting the APIs from the custom element manifest.
type BaseElementConfig<T> = {
/** The heading for the section */
heading?: string;
/** The ID used for the skip-link */
headingId?: string;
/** The label used for the skip-link */
skipLinkLabel?: string;
/** The description for the section */
headings?: string[];
/** The description for the section */
description?: string;
/** The table row template for the section */
rowTemplate?: (x: T) => string;
};Markdown Support
Many of the JSDoc comments support markdown. To parse markdown in these API blocks, you can use the markdownToHtml utility helper provided by this project or you can install and use your own.
The package uses marked internally for markdown parsing. You can use the built-in helper:
import { markdownToHtml, setWcDoxConfig } from 'wc-dox/index.js';
setWcDoxConfig(manifest, {
props: {
rowTemplate: prop =>
`<tr>
<td><code>${prop.name}</code></td>
<td>${markdownToHtml(prop.description || '')}</td>
</tr>`,
},
});CSS Parts Element Config
type CssPart = cem.CssPart & Record<string, any>;
type CssPartsElementConfig = BaseElementConfig<CssPart>;The default value for this is:
cssParts: {
heading: 'CSS Parts',
headingId: 'css-parts',
skipLinkLabel: 'Skip to CSS parts',
description:
'The following [CSS shadow parts](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_shadow_parts) are available to customize the component:',
headings: ['Name', 'Description', 'Deprecated'],
rowTemplate: cssPart =>
`<tr>
<td><p><code>${cssPart.name}</code></p></td>
<td>${markdownToHtml(cssPart.description || '')}</td>
<td style="text-align: center;">${cssPart.deprecated ? '✔️' : ''}</td>
</tr>`,
},CSS Props Element Config
type CssPropsElementConfig = BaseElementConfig<CssProp>;
type CssProp = cem.CssCustomProperty & Record<string, any>;The default value for the CSS Custom Properties Element is:
cssProps: {
heading: 'CSS Custom Properties',
headingId: 'css-props',
skipLinkLabel: 'Skip to CSS custom properties',
description:
'You can use [CSS custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties) to customize the look and feel of the component using the following properties:',
headings: ['Name', 'Default', 'Description', 'Deprecated'],
rowTemplate: cssVar =>
`<tr>
<td><p><code>${cssVar.name}</code></p></td>
<td><p><code>${cssVar.default}</code></p></td>
<td>${markdownToHtml(cssVar.description || '')}</td>
<td style="text-align: center;">${cssVar.deprecated ? '✔️' : ''}</td>
</tr>`,
},Events Element Config
type EventsElementConfig = BaseElementConfig<Event>;
type Event = cem.Event & Record<string, any>;The default value for the Events Element is:
events: {
heading: 'Events',
headingId: 'events',
skipLinkLabel: 'Skip to events',
description:
'The following [events](https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events) are emitted by the component:',
headings: ['Name', 'Type', 'Description', 'Deprecated'],
rowTemplate: event =>
`<tr>
<td><p><code>${event.name}</code></p></td>
<td><p><code>${event.type.text === 'CustomEvent' ? 'CustomEvent' : `CustomEvent<${event.type.text}>`}</code></p></td>
<td>${markdownToHtml(event.description || '')}</td>
<td style="text-align: center;">${event.deprecated ? '✔️' : ''}</td>
</tr>`,
},Methods Element Config
type MethodsElementConfig = BaseElementConfig<Method>;
type Method = cem.ClassMethod & Record<string, any>;The default value for the Methods Element is:
methods: {
heading: 'Methods',
headingId: 'methods',
skipLinkLabel: 'Skip to methods',
description: 'The following Methods are available:',
headings: ['Name', 'Description', 'Deprecated'],
rowTemplate: method => {
const getParameter = (p: Parameter) => p.name + getParamType(p) + getParamDefaultValue(p);
const getParamType = (p: Parameter) => p.type?.text ? `${p.optional ? '?' : ''}: ${p.type?.text}` : '';
const getParamDefaultValue = (p: Parameter) => p.default ? ` = ${p.default}` : '';
return `<tr>
<td><p><code>${method.name}(${method.parameters?.map(p => getParameter(p)).join(', ') || ''}) => ${method.return?.type?.text || 'void'}</code></p></td>
<td>${markdownToHtml(method.description || '')}</td>
<td style="text-align: center;">${method.deprecated ? '✔️' : ''}</td>
</tr>`;
}
},Props Element Config
type PropsElementConfig = BaseElementConfig<Property>;
type Method = cem.ClassMethod & Record<string, any>;The default value for the Props Element is:
props: {
heading: 'Attributes and Properties',
headingId: 'props',
skipLinkLabel: 'Skip to attributes and properties',
description: 'The following Properties and Attributes are available:',
headings: [
'Name',
'Attribute',
'Description',
'Type',
'Default',
'Read-only',
'Deprecated',
],
rowTemplate: prop =>
`<tr>
<td><p><code>${prop.name}</code></p></td>
<td><p><code>${prop.attribute || ''}</code></p></td>
<td>${markdownToHtml(prop.description || '')}</td>
<td><p><code>${prop.type?.text || ''}</code></p></td>
<td><p><code>${prop.default}</code></p></td>
<td style="text-align: center;">${prop.readonly ? '✔️' : ''}</td>
<td style="text-align: center;">${prop.deprecated ? '✔️' : ''}</td>
</tr>`,
},Slots Element Config
type SlotsElementConfig = BaseElementConfig<Slot>;
type Slot = cem.Slot & Record<string, any>;The default value for the Slots Element is:
slots: {
heading: 'Slots',
headingId: 'slots',
skipLinkLabel: 'Skip to slots',
description: 'The following slots are available:',
headings: ['Name', 'Description', 'Deprecated'],
rowTemplate: slot =>
`<tr>
<td><p><code>${slot.name || '<em>(default)</em>'}</code></p></td>
<td>${markdownToHtml(slot.description || '')}</td>
<td style="text-align: center;">${slot.deprecated ? '✔️' : ''}</td>
</tr>`,
},CssStatesElementConfig
type CssStatesElementConfig = BaseElementConfig<CssState>;
type CssState = cem.CssCustomState & Record<string, any>;The default value for the CSS States Element is:
cssStates: {
heading: 'CSS States',
headingId: 'css-states',
skipLinkLabel: 'Skip to CSS states',
description:
'The following [CSS states](https://developer.mozilla.org/en-US/docs/Web/CSS/:state) can be used to customize component styles:',
headings: ['Name', 'Description', 'Deprecated'],
rowTemplate: state =>
`<tr>
<td><p><code>${state.name}</code></p></td>
<td>${markdownToHtml(state.description || '')}</td>
<td style="text-align: center;">${state.deprecated ? '✔️' : ''}</td>
</tr>`,
},Styling
The components render their content in the Light DOM, which means you can easily apply your own styles. The package includes a CSS custom property for controlling spacing:
wc-dox {
--wc-dox-content-gap: 2rem; /* Default spacing between sections */
}You can also use the headingClass and tableClass configuration options to add custom classes to the generated elements for easier styling.
Troubleshooting
No documentation appears
- Ensure you've called
setWcDoxConfig(manifest)before rendering the components - Verify that your custom elements manifest is valid JSON
- Check that the
tagorcomponent-nameattribute matches an entry in your manifest - Inspect the browser console for any errors
Documentation is empty or missing sections
- By default, empty sections are hidden. Set
hideOnEmpty: falseto show them - Verify your custom elements manifest includes the expected metadata (properties, events, etc.)
- Ensure your components are properly documented with JSDoc comments
Markdown not rendering
- Make sure you're using the
markdownToHtmlhelper in your customrowTemplatefunctions - Check that markdown content is valid
TypeScript import errors
- Ensure you're importing from the correct paths:
wc-dox/index.jsfor the main module - Type definitions are included automatically from
index.d.ts
TypeScript Support
The package is written in TypeScript and includes type definitions. You can import types for configuration and custom element manifest structures:
import type {
DoxConfig,
BaseElementConfig,
CssPartsElementConfig,
CssPropsElementConfig,
CssStatesElementConfig,
EventsElementConfig,
MethodsElementConfig,
PropsElementConfig,
SlotsElementConfig,
ImportsElementConfig,
DoxElementConfig,
// Type aliases for manifest data
CssPart,
CssProp,
Event,
Method,
Property,
Slot,
CssState,
} from 'wc-dox';Package Exports
The package provides multiple entry points:
wc-dox- Main entry point with all web componentswc-dox/react- React wrapper componentswc-dox/index.js- ES module for direct importwc-dox/cdn/index.js- CDN-optimized bundle
All components are automatically registered as custom elements when imported.
Browser Support
This package uses modern web standards and requires:
- ES2015+ support
- Custom Elements v1
- Shadow DOM v1
All modern browsers (Chrome, Firefox, Safari, Edge) are supported. For older browsers, you may need polyfills.
Examples
Basic Usage with Multiple Components
<!DOCTYPE html>
<html>
<head>
<script type="module">
import { setWcDoxConfig } from 'wc-dox/index.js';
import manifest from './custom-elements.json' with { type: 'json' };
setWcDoxConfig(manifest);
</script>
</head>
<body>
<h1>My Button Component</h1>
<wc-dox tag="my-button"></wc-dox>
<h1>My Input Component</h1>
<wc-dox tag="my-input"></wc-dox>
</body>
</html>Customized Configuration
import { setWcDoxConfig, markdownToHtml } from 'wc-dox/index.js';
import manifest from './custom-elements.json' with { type: 'json' };
setWcDoxConfig(manifest, {
headingLevel: 2,
headingClass: 'api-heading',
tableClass: 'api-table',
hideOnEmpty: true,
dox: {
apiOrder: ['props', 'events', 'methods', 'slots', 'css-props', 'css-parts'],
},
props: {
heading: 'Properties & Attributes',
description: 'Configure the component using these properties:',
},
events: {
heading: 'Custom Events',
description: 'Listen for these events:',
},
});Individual Component Usage
<!-- Only show properties documentation -->
<wc-props tag="my-element"></wc-props>
<!-- Only show events documentation -->
<wc-events tag="my-element"></wc-events>
<!-- Show imports with custom configuration -->
<wc-imports tag="my-element"></wc-imports>Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License - see the LICENSE file for details.
Related Projects
- Custom Elements Manifest - The schema and spec
- @custom-elements-manifest/analyzer - Generate custom elements manifests
- Lit - The library used to build these components
Changelog
See CHANGELOG.md for version history and updates.
