Markdown Pages are .rocket.md files with Page setup code plus Markdown content. Use them for
durable content, documentation, tutorials, landing pages, and component reference Pages that can
render ahead of time.
Start a Markdown Page with a js server fence that exports Page setup:
```js server
export const config = {
path: '/components/button',
metadata: { title: 'Button' },
};
export { layout } from '@rocket/js/layout.js';
```
# Button
The Button Page is written in Markdown.
The config.path value controls the public route path. The file can live anywhere matched by
includeGlobs.
js server code runs while Rocket loads and renders the Page. Use it for imports, Page config,
layouts, Registered Components, and values that Markdown should interpolate:
```js server
import { resolve } from '@rocket/js/resolve.js';
export const config = {
path: '/brand',
metadata: { title: 'Brand' },
};
const logo = resolve('../assets/logo.svg', import.meta);
```
<img src="${logo}" alt="Brand logo" />
Prefer one setup block near the top of the Page. Multiple js server blocks are possible, but a
single block keeps the Page setup easy to scan.
js client code is emitted as browser module code for that Page:
```js client
class InlineCounter extends HTMLElement {
connectedCallback() {
this.innerHTML = '<button type="button">Count: 0</button>';
}
}
customElements.define('inline-counter', InlineCounter);
```
<inline-counter></inline-counter>
Use js client for Page-local Custom Elements, small browser behavior, and shared imports for
js demo blocks. Code in js client is not displayed as content.
js demo code blocks create JavaScript Demos and Standalone Demo URLs:
```js client
import { html } from 'lit';
```
```js demo
export const primaryButton = () => html``;
```
Each demo should export a named function. Demo names should be unique within the Markdown Page.
Rocket renders demos inside <rocket-js-demo> on the parent Page and also generates a Standalone
Demo URL:
<page path>/_demo/<demo export name>/
Use Demos for the full behavior, including source controls, shared setup, and collision rules.
Markdown Pages support standard Markdown, GitHub-flavored Markdown, and raw HTML:
## Usage
Use **strong copy** for important guidance.
<aside>
This raw HTML stays part of the rendered Page.
</aside>
Markdown text can interpolate values from js server scope. Expressions inside fenced code examples
are displayed as code instead of being evaluated.
Each Markdown Page should have one h1. Rocket uses it as a fallback title and builds the table of
contents from the remaining headings.
Rocket gives each rendered heading an id and appends a permalink anchor so readers can share a
specific section URL.
Heading levels should move one level at a time:
# Page
## Section
### Detail
Use link-text to change menu or table-of-contents text:
<h2 link-text="API">Application Programming Interface</h2>
Use menu-exclude to leave a heading out of the table of contents:
<h2 menu-exclude>Internal implementation note</h2>
When Markdown content contains an authored custom element tag with a hyphen, the Page must own that tag in one of two ways.
Register reusable files through the Page's components export:
const cardFile = new URL('../components/AcmeCard.js', import.meta.url).href;
export const components = {
'acme-card': {
file: cardFile,
className: 'AcmeCard',
loading: 'server',
},
};
Or define a Page-local Custom Element in the same Page's js client code:
class InlineCounter extends HTMLElement {}
customElements.define('inline-counter', InlineCounter);
The same tag cannot be both a Registered Component and a Page-local Custom Element. Tags used only
inside js demo blocks do not satisfy ownership for tags in the parent Markdown content.
Markdown Pages build to static HTML by default:
export const config = {
path: '/docs/button',
};
Use render: 'server' only when the Markdown Page itself must render at request time:
export const config = {
path: '/docs/request-shaped',
render: 'server',
};
Server-rendered Markdown Pages need a deployment adapter in production.