Skip to content
Benny Powers edited this page Jul 7, 2022 · 1 revision

Use JSDoc to document your element classes. JSDoc information surfaces in a variety of places and helps design system contributors and users understand your elements.

  • A system contributor is refactoring a component template. They notice a call to a protected method on the super class. They use their editor's language server hover feature to view the JSDoc description of the method. This helps them understand whether and how to override it.
  • A system user wants to customize an instance of an element in an app view. Reading the component's available CSS parts and properties on ux.redhat.com helps them understand how to customize the element's appearance on the page.

Every public method and property should have a docstring. For CSS custom properties, shadow parts, slot names, and events, document those on the class' docblock.

Be aware that the @cssprop, @slot, @csspart block tags; and @default and @value inline tags are non-standard JSDoc, which we parse with our own analyzer plugin.

Ordering

Component authors may adhere to the following class-level JSDoc tag ordering convention:

  1. Slots
  2. CSS shadow parts
  3. Events
  4. CSS custom properties

Slots and parts may be interleaved if they are directly linked e.g.

/**
 * @slot    header - Card header
 * @csspart header - Card header container
 */

Slots

Use the following template to document slots

/**
 * @slot name - Description
 * @slot      - Description
 */

Slot tags may be split across lines for readability

/**
 * @slot name
 *       A long description requiring much verbiage to convey meaning.
 *       Though generally discouraged, there are times where verbosity is praiseworthy
 * @slot
 *       The default slot for this element requires extended prose to fully convey its meaning
 *       ```html
 *       <rh-jazz-hands>
 *         <p>We may even provide markdown-formatted examples
 *       </rh-jazz-hands>
 *       ```
 */

name is the slot name, or blank space in the case of the anonymous slot. Description is a terse, declarative sentence fragment, e.g. "Content for the tooltip popup". Since we lack a robust enough type syntax to describe slotted content restrictions, describe them in prose instead.

  • DON'T use a jsdoc {type} annotation to specify content requirements
  • DO list content requirements in the description
    // BAD
    /**
     * @slot {HTMLButtonElement} trigger - Trigger to start the upload
     */
    
    // Good
    /**
     * @slot trigger
     *       Trigger to start the upload.
     *       Must be a button-like element
     */

CSS Shadow Parts

Use the following template to document parts:

/**
 * @csspart name - Description
 */

CSS part tags may be split across lines for readability:

/**
 * @csspart name
 *          A long description requiring much verbiage to convey meaning.
 *          Though generally discouraged, there are times where verbosity is praiseworthy,
 *          For example, when a markdown snippet is deemed necessary
 *          ```css
 *          rh-jazz-hands::part(left hand) {
 *            animation-duration: 100ms;
 *          }
 *          ```
 */

Events

Document all events dispatched by your element. Use the @fires tag with a type annotation and description, according to this template:

/**
 * @fires {type} name - Description
 */

Event tags may be split across lines for readability:

/**
 * @fires {type} name
 *               A long description requiring much verbiage to convey meaning.
 *               Though generally discouraged, there are times where verbosity is praiseworthy,
 *               For example, when a markdown snippet is deemed necessary
 *               ```javascript
 *               jazzHands.addEventListener('select', ({ era }) => toast.show(`${era} selected!`);
 *               ```
 */

CSS Custom Properties

Document all CSS Custom Properties with the @cssprop tag using this template:

/**
 * @cssprop {type} --name - Description {@default `value`} {@deprecated reason}
 */

Tags may be split across lines for readability

/**
 * @cssprop {type} --name
 *          Description
 *          {@default `value`}
 *          {@deprecated reason}
 */

In the above template,

  • type is a CSS data type, and optional if the type is long or unwieldy
  • --name is the CSS custom property name
  • description is a terse, declarative sentence fragment, formatted using markdown
  • value is the default value
  • reason is the reason for deprecation, e.g. "use --new-name instead"

The @default and @deprecated tags are optional, but if the variable supplies a default, it should be documented.

CSS Values and Tokens

When documenting CSS values in the {@default} inline tag, surround the value with backticks, e.g. {@default `1rem`}. Specify default values directly, without referencing variable stacks. If you wish to document the variable stack, do so using the {@link} inline tag

  • DON'T paste entire variable stacks
  • DO reference design tokens in @link
    // BAD
    /**
     * @cssprop {color} --close-button-background
     *          Background for the optional close button
     *          {@default `var(--rh-color-interactive-blue-lightest, var(--rh-color-blue-100, #bee1f4))`}
     */
    
    // Good
    /**
     * @cssprop {color} --close-button-background
     *          Background for the optional close button
     *          {@link --rh-color-interactive-blue-lightest}
     *          {@default `#bee1f4`}
     */

Classes

All public and protected class members (fields and methods) must have a JSDoc annotation. Private class members may use a doc block, but it is not required. When using TypeScript parameter properties, document them inline as you would any other class field.

export class RHJazzHandsSelectEvent extends Event {
  constructor(/** The jazz era selected */ public era: 'ragtime'|'golden'|'smooth') {
    super('select');
  }
}

Class Fields

Class fields decorated with lit's @property decorator will automatically be documented as attribute/property pairs, according to the configuration object passed to the decorator. So there's no need to annotate a so-decorated class field with @attr. @type should be avoided, instead use TypeScript types. So for most cases, the JSDoc annotation should be a terse declarative description of the field. For boolean fields, it's only necessary to describe the true state

  • DO use TypeScript typings
  • DON'T use @type
  • DON'T use @attr for @property-decorated fields
  • DON'T over-explain booleans
    // BAD
    /**
     * When true, the dialog is open. When false, the dialog is closed
     * @attr open
     * @type {boolean}
     */
    @property({ type: Boolean, reflect: true, attribute: 'open' }) open: boolean = false;
    
    // GOOD
    /** Whether the dialog is open */
    @property({ type: Boolean, reflect: true }) open = false;

Methods

Public and protected methods must be documented. Private methods may be documented, but it is not strictly required. Parameters and return types may be documented if their meaning is not clear from the type. JSDoc annotations should not contain type information.

  • DO describe public and protected methods
  • DO optionally describe private methods, when their use isn't clear
  • DON'T echoing type information in parameter and return annotations
    // BAD
    /**
     * Shows the dialog
     * @param {boolean} autoclose boolean flag
     * @return {Promise<void>} a promise with no value
     */
    async show(autoclose: boolean): Promise<void> {/*..*/}
    
    // GOOD
    /**
     * Shows the dialog
     * @param autoclose whether the dialog should close automatically after `autoCloseDelay`
     * @return resolves when the open animation completes
     */
    async show(autoclose: boolean): Promise<void> {/*..*/}
Clone this wiki locally