On this page

doc-kit reads GitHub Flavored Markdown, plus a handful of conventions that turn a page into an API reference: headings written as signatures, typed parameter lists, version history and stability. This page covers what most documents use. The Markdown specification is the full contract.

Tip

Documenting a TypeScript or JavaScript project? @doc-kit/typedoc writes this Markdown for you, from your source code and its JSDoc comments. See Documenting TypeScript.

# Kittens

The `kittens` module adopts, feeds and pets kittens.

Start every file with one level-one heading. Its text is the page's title: it names the browser tab and, unless you configure the sidebar yourself, the page's link in the sidebar. The website skips a file that has headings but no level-one heading. The first paragraph is the page's description, which llms.txt lists next to the link.

The output file follows the source path, not the title: with docs/**/*.md as input, docs/kittens.md becomes kittens.html.

Everything GitHub Markdown does still works. On top of it:

  • Text in curly braces is a type annotation: {string} renders as code that links to the type's documentation. Put literal braces in a code span.
  • Headings written like signatures, such as `kittens.adopt(name)`, are API entries.
  • A list under an entry whose items start with a name and a type is a typed list.
  • HTML comments carry metadata: <!-- YAML blocks record history, and <!--key=value--> comments set page metadata.
  • A blockquote that starts with Stability: is a stability indicator.
  • Two or more code blocks in a row become tabs.
  • Links to .md files point to the generated pages.

Each heading below the title, down to #####, starts an entry, and deeper headings start entries nested inside it. An entry has up to six parts, in this order: a heading, its history, its stability, its typed list, prose, and code samples. All but the heading come before the next heading, whatever its level.

docs/kittens.md## `kittens.adopt(name[, options])`<!-- YAMLadded: v1.0.0-->> Stability: 1 - Experimental- `name` {string}- `options` {Object}  - `color` {string}    **Default:** `'tabby'`.- Returns: {Promise}Adopts a kitten.```jsawait kittens.adopt('Mittens');```1 Heading2 History3 Stability4 Typed list5 Prose6 Code sampleEntrykittens.htmlMkittens.adoptHistorykittens.adopt(name, options?): PromiseStability: 1Experimentalname:stringoptions:Objectcolor?:stringDefault: 'tabby'Returns:PromiseAdopts a kitten.await kittens.adopt('Mittens');123456

Every part after the heading is optional, and most entries use only a few:

## `kittens.adopt(name[, options])`

<!-- YAML
added: v1.0.0
-->

- `name` {string} The kitten's name.
- `options` {Object}
  - `color` {string} Coat color. **Default:** `'tabby'`.
- Returns: {Promise} Fulfills with the adopted kitten.

Adopts a kitten, once the paperwork is done.

```js
const kitten = await kittens.adopt('Mittens');
```

The heading makes this a method and gives its signature, the comment records when it was added, and the list becomes its parameters and return value. The website renders a signature, a parameter table and a version history; the JSON output keeps each part as data.

doc-kit reads an entry's kind from its heading, with no annotation needed:

HeadingKind
## Class: `kittens.Kitten`Class
### `new kittens.Kitten(name)`Constructor
### Static method: `Kitten.from(json)`Static method
### `kitten.pet([times])`Method
### `kitten.name`Property
### Event: `'purr'`Event
  • Parentheses make a method, and their absence a property. A method needs only a name, as in `adopt(name)`, but a property needs an owner: `kitten.name` or `kitten[key]`.
  • The Class:, Static method: and Event: prefixes mark those kinds, and new marks a constructor.
  • The code span must be the whole heading, after any prefix: ### `kitten.pet()` again is a plain section.
  • Optional parameters go in square brackets, nested when one only makes sense after another: `kitten.groom(brush[, side[, strokes]])`. A rest parameter is written [...names]. Leave types and defaults out of the heading; they belong in the typed list.
  • Anything else, like ## Synopsis, is a plain section. Write those headings in plain words, without backticks.

Entries nest by heading level, so put a class's constructor, methods, properties and events one level below the class.

Under the heading, and after any history or stability, a typed list describes what the entry takes and returns. Each item is a name in a code span, a type in curly braces, and a description:

### `kitten.feed(food[, options])`

- `food` {string|string[]} What to serve.
- `options` {Object}
  - `portion` {number} Grams per serving. **Default:** `50`.
  - `signal` {AbortSignal} Cancels the meal.
- Returns: {Promise<boolean>} Fulfills with `true` once the bowl is empty.
  • Nested lists describe the properties of an object, to any depth.
  • **Default:** followed by the value in a code span records a default and makes the parameter optional. Square brackets in the heading make it optional too.
  • Three prefixes stand in for the name: Returns: for a return value, Type: for a property's type, and Extends: for a class's parent class.

The same list works for the other kinds. An event's list describes the arguments its listeners receive:

## Class: `kittens.Kitten`

- Extends: {EventTarget}

### `kitten.name`

- Type: {string}

### Event: `'purr'`

- `volume` {number} How loud, from 1 to 10.

doc-kit recognizes a typed list by its first item, which must start with a name and a type, a bare type, or one of the prefixes. A list whose first item has a name but no type stays a plain list, and plain bullets after the typed items stay prose.

On the website, a typed list becomes a table, under the signature for methods and constructors. In JSON, each item's name, type, description, default and whether it's optional become fields.

Curly braces hold a TypeScript type, in a typed list or anywhere in prose. doc-kit renders it as code and links each type name in it to its documentation:

- `food` {string|string[]} What to serve.

`kittens.adopt()` returns a {Promise} that fulfills with a {kittens.Kitten}.

Anything valid on the right of a TypeScript type X = works, including unions, arrays and generics such as {Promise<boolean>}. doc-kit looks each name up in order, and the first match wins:

  1. Your type map. Its names are case-sensitive and may contain spaces.
  2. JavaScript primitives and keywords, such as string, number, null and any, linked to MDN.
  3. JavaScript's built-in objects and the Web APIs documented on MDN, such as Promise, Map, AbortSignal and URL.
  4. Dotted names, which link into your own docs: the part before the first dot names the page. {kittens.Kitten} links to the Class: heading on the kittens page (a capitalized last part means a class), and {kittens.breeds} to the kittens.breeds property.

Steps 2 and 3 ignore case. A name that nothing matches stays plain text inside the code, which is fine. If the braces don't hold a valid type, doc-kit logs a warning and renders the text as plain code.

For your own types, and other projects' types, write a JSON file that maps names to URLs:

{
  "Litter": "https://example.com/docs/litter",
  "Adoption options": "kittens.html#kittensadoptname-options"
}

Then point metadata.typeMap at it, or pass it to the CLI's --type-map option:

export default {
  metadata: {
    typeMap: './type-map.json',
  },
};

typeMap takes a URL, or a path read from the directory you run doc-kit in. A relative URL in the map is relative to the output root, and doc-kit adjusts it for each page.

An HTML comment that starts with YAML, right after an entry's heading, records the entry's history:

### `kittens.adopt(name[, options])`

<!-- YAML
added: v1.0.0
changes:
  - version: v2.0.0
    pr-url: https://github.com/you/kittens/pull/42
    description: The `color` option accepts any CSS color.
deprecated: v3.0.0
-->
FieldWhat it records
addedThe version the entry first shipped in.
deprecatedThe version that deprecated it.
removedThe version that removed it.
changesNotable changes, each with a version, a pr-url and a description (Markdown).

A version is a string such as v1.0.0. Use a list of versions for a change that was backported to older release lines. The website shows the history next to the heading, and JSON keeps it as data.

A blockquote that starts with Stability:, a level and a label marks an entry's stage in its lifecycle. The website renders it as a colored box, like this one:

Stability: 2Stable. This box is a live stability indicator.

Place it after the history comment, if there is one, and before the typed list. The text after the level is yours: explain, link to an alternative, or continue on more lines.

### `kittens.adopt(name[, options])`

<!-- YAML
added: v1.0.0
-->

> Stability: 1 - Experimental. The adoption fee may change.

- `name` {string} The kitten's name.
LevelMeaning
0Deprecated: may emit warnings, and compatibility isn't guaranteed.
1Experimental: outside semantic versioning, and may change in any release.
2Stable: compatibility is a priority.
3Legacy: still covered by semantic versioning, but no longer maintained.

Level 1 takes sub-levels that say how close an API is to stable: 1.0 (early development), 1.1 (active development) and 1.2 (release candidate). On the title, a stability indicator applies to the whole page.

Fence code samples with a language, so the website can highlight them. Two or more code blocks in a row become one block with a tab each. A tab is labelled by its block's displayName, or by its language when it has none (cjs and mjs read as CJS and ESM):

```bash displayName="npm"
npm install kittens
```

```bash displayName="pnpm"
pnpm add kittens
```

That renders as:

To keep blocks apart, put a sentence between them. The JSON output lists each entry's code samples, with their language and displayName.

GitHub's alert syntax renders as a callout, like the tip at the top of this page:

> [!WARNING]
> Kittens adopted before eight weeks of age need extra care.

The five kinds are NOTE, TIP, IMPORTANT, WARNING and CAUTION.

Link to other pages by their source file, with a relative path. doc-kit rewrites the .md extension to the output's .html:

See [`kittens.adopt()`][] for the details, or the [care guide](care.md).

[`kittens.adopt()`]: kittens.md#kittensadoptname-options

Anchors are heading slugs, made much as GitHub makes them: ## `kittens.adopt(name[, options])` becomes #kittensadoptname-options, and ## Class: `kittens.Kitten` becomes #class-kittenskitten. When in doubt, copy the link from the heading on the rendered page.

Reference-style links, with their definitions at the end of the file, keep long pages readable. A system call written like open(2) in plain text (not in a code span) links to its Linux manual page.

One-line comments right after the title set metadata for the whole page:

# Kittens

<!--introduced_in=v1.0.0-->
<!--source_link=lib/kittens.js-->
<!--llm_description=Adopt, feed and pet kittens.-->
DirectiveWhat it does
introduced_inThe version the module first shipped in, shown with the page's history.
source_linkLinks the page to the file that implements it, in your repository on GitHub.
llm_descriptionDescribes the page in llms.txt, in place of its first paragraph.
typeWhat the page documents: module (the default), misc or global.
nameThe module's name in JSON output, when it isn't the file name.

A frontmatter block at the top of the file does the same job with YAML keys: any of the directives above or the history fields, plus title, which replaces the heading's text in the browser tab, and mdx, described in MDX pages.

---
title: Adopting kittens
introduced_in: v1.0.0
---

# Kittens

Guides need nothing special: headings that don't look like an API stay plain sections. Still, doc-kit treats every page as documenting a module unless its type directive says otherwise:

# Caring for your kitten

<!--type=misc-->

misc marks a guide or another conceptual page: JSON output records the page's type as misc, with no module name. global marks a page of globals, which need no import, and JSON gives its entries a global scope.

The directive doesn't change how headings are classified: on a misc page, ## `kitten.pet()` is still a method. When a heading looks like an API but isn't an entry, write it in plain words, or override its kind in its YAML comment so that it becomes a plain section:

### `kitten.whiskers`

<!-- YAML
type: misc
-->

When a page needs components, such as a landing page or a live demo, write it in MDX: name the file .mdx, or set mdx: true in a Markdown file's frontmatter (mdx: false turns an .mdx file back into Markdown).

---
title: Kittens
---

# Kittens

Everything about adopting, feeding and petting kittens.

<DocumentationIndex />

<DocumentationIndex /> is built in: it lists every page with its stability and description. Components you register yourself work too; see Customizing the site.

In MDX, curly braces are JavaScript expressions, not types, so typed lists stay plain lists and type names don't link. HTML comments aren't valid MDX either, so set page metadata in frontmatter, write comments as {/* ... */}, and keep entries that need history in Markdown pages. Headings and stability indicators work as they do in Markdown.