---
title: 'Write guides for Video.js'
description: 'A guide on writing documentation, and a test bed for all our MDX components'
---

import FrameworkCase from '@/components/docs/FrameworkCase.astro';
import StyleCase from '@/components/docs/StyleCase.astro';
import MinimalFrame from '@/components/frames/Minimal.astro';
import ServerCode from '@/components/Code/ServerCode.astro';
import { TabsRoot, TabsList, TabsPanel, Tab } from '@/components/Tabs.tsx';
import DocsLink from '@/components/docs/DocsLink.astro';
import Aside from '@/components/Aside.astro';

What is a guide? In this context, it's a document in the docs that's not an API reference. For API references, see <DocsLink slug="reference/write-references">Write reference pages</DocsLink>.

<Aside type="tip">
Oh hey by the way. A lot of this knowledge is encoded in the `docs-guide` Claude skill. You should still read it, but, now your LLM can help you along the way, too.
</Aside>

## 1. Understand our documentation structure

First, read and understand [Diátaxis](https://diataxis.fr/). We organize documentation into three modes:

1. **Concept pages** (`src/content/docs/concepts/`): Explain how and why things work. General understanding, spanning multiple APIs, can be applied to multiple outcomes. As we write guides, what are things we need people to understand in multiple places and don’t want to duplicate the content?
2. **How-to guides** (`src/content/docs/how-to/`): Spans multiple concepts in order to achieve a specific outcome with step-by-step instructions. 
3. **Reference pages** (`src/content/docs/reference/`): Component API documentation. These are scaffolded using the `api-reference` skill and the api-docs-builder. Again, see <DocsLink slug="reference/write-references">Write reference pages</DocsLink> for details.

When in doubt, you probably want a concept page.

## 2. Create a guide in the correct content folder

Our guides are [MDX](https://mdxjs.com) files placed in the matching directory:

- Concept pages go in `src/content/docs/concepts/[slug].mdx`
- How-to guides go in `src/content/docs/how-to/[slug].mdx`

## 3. Add that guide to the sidebar

Next, open `src/docs.config.ts` and add your guide to the appropriate section of the sidebar. For example, to add a how-to guide on "Writing guides", you would add:

```ts
{
  slug: 'how-to/write-guides',
  title: 'Writing guides'
}
```

If you want the guide to only apply to specific frameworks or styles, you can specify those as well:

```ts
{
  slug: 'how-to/write-guides',
  title: 'Writing guides',
  frameworks: ['react'], // Only for React
  styles: ['css'] // Only for CSS
}
```

## 4. Follow our writing style

Keep documentation clear, human, and useful. Here are the key rules:

- **Sentence case for headings** — capitalize only the first word and proper nouns (e.g., "Choose your JS framework", not "Choose Your JS Framework")
- **Active voice, second person** — speak directly to the reader with "you"
- **Collaborative pronouns** — use "we," "us," and "our" when talking about the project or team
- **Avoid gerunds in headings** — prefer "Write good headings" over "Writing good headings"
- **Oxford comma** — always use the serial comma in lists of three or more
- **Gender-neutral language** — use "they" or "their" instead of "his" or "her"
- **Cut filler words** — remove "In order to," "basically," "simply," "might," "could," "perhaps"
- **Be precise** — make claims as strong as possible without becoming false; avoid vague qualifiers like "somewhat" or "fairly"
- **Read it out loud** — if it sounds awkward, rewrite it

## 5. Understand MDX and our components

### `<FrameworkCase>` and `<StyleCase>`
First, understand that the guide you write will be rendered for every framework / style combination (e.g., HTML + CSS, React + CSS) unless you restrict it in the sidebar config as shown above.

Use the `<FrameworkCase>` and `<StyleCase>` components to conditionally show content to just one framework or style:

```mdx
<FrameworkCase frameworks={["react"]}>
  React-only content
</FrameworkCase>
```


<FrameworkCase frameworks={["react"]}>
  React-only content
</FrameworkCase>

<Aside type="note">
If you see nothing, that means you probably don't have React selected as your framework. Cool! It's working!
</Aside>

Use the `<StyleCase>` component to show content only for specific styling approaches. For example,

```mdx
<StyleCase styles={["css"]}>
  CSS-only content
</StyleCase>
```


<StyleCase styles={["css"]}>
  CSS-only content
</StyleCase>

<Aside type="note">
If you see nothing, that means you probably don't have CSS selected as your style. Cool! It's working!
</Aside>

## Use Github-Flavored Markdown

### Headings

Don't use H1 (or in markdown, `# H1`). We already have an H1 at the top of the page. Do, however, check out H2 (`## H2`) through H6 (`###### H6`).


## H2 with `code`

### H3 with `code`

#### H4 with `code`

##### H5 with `code`

###### H6 with `code`

### Paragraph

Xerum, quo qui aut unt expliquam qui dolut labo. Aque venitatiusda cum, voluptionse latur sitiae dolessi aut parist aut dollo enim qui voluptate ma dolestendit peritin re plis aut quas inctum laceat est volestemque commosa as cus endigna tectur, offic to cor sequas etum rerum idem sintibus eiur? Quianimin porecus evelectur, cum que nis nust voloribus ratem aut omnimi, sitatur? Quiatem. Nam, omnis sum am facea corem alique molestrunt et eos evelece arcillit ut aut eos eos nus, sin conecerem erum fuga. Ri oditatquam, ad quibus unda veliamenimin cusam et facea ipsamus es exerum sitate dolores editium rerore eost, temped molorro ratiae volorro te reribus dolorer sperchicium faceata tiustia prat.

Itatur? Quiatae cullecum rem ent aut odis in re eossequodi nonsequ idebis ne sapicia is sinveli squiatum, core et que aut hariosam ex eat.

### Images

```mdx
![alt text](../path/to/local/or/remote/image)
```

![All four Video.js themes](../../../assets/blog/2019-09-13-announcing-the-new-videojs-com/collage.png)

### Blockquotes

The blockquote element represents content that is quoted from another source, optionally with a citation which must be within a `footer` or `cite` element, and optionally with in-line changes such as annotations and abbreviations.

```markdown
> Tiam, ad mint andaepu dandae nostion secatur sequo quae.
> **Note** that you can use _Markdown syntax_ within a blockquote.
```

> Tiam, ad mint andaepu dandae nostion secatur sequo quae.
> **Note** that you can use _Markdown syntax_ within a blockquote.

### Footnotes

```markdown
> Don't communicate by sharing memory, share memory by communicating.<br/>
> — <cite>Rob Pike[^1]</cite>
```

> Don't communicate by sharing memory, share memory by communicating.<br/>
> — <cite>Rob Pike[^1]</cite>

[^1]: The above quote is excerpted from Rob Pike's [talk](https://www.youtube.com/watch?v=PAAkCSZUG1c) during Gopherfest, November 18, 2015.

### Tables

```markdown
| Italics   | Bold     | Code   |
| --------- | -------- | ------ |
| _italics_ | **bold** | `code` |
```


| Italics   | Bold     | Code   |
| --------- | -------- | ------ |
| _italics_ | **bold** | `code` |

When a table is really wide, it overflows nicely on mobile

| A | Table | With | A | Lot | Of | Columns |
| --- | --- | --- | --- | --- | --- | --- |
| contentcontentcontent | contentcontentcontent | contentcontentcontent | contentcontentcontent | contentcontentcontent | contentcontentcontent | contentcontentcontent |

### Code blocks

we can use 3 backticks ``` in new line and write snippet and close with 3 backticks on new line and to highlight language specific syntax, write one word of language name after first 3 backticks, for eg. html, javascript, css, markdown, typescript, txt, bash

````markdown
```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Example HTML5 Document</title>
  </head>
  <body>
    <p>Test</p>
  </body>
</html>
```
````


```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Example HTML5 Document</title>
  </head>
  <body>
    <p>Test</p>
  </body>
</html>
```

### List types

#### Ordered list

```markdown
1. First item
2. Second item
3. Third item
```

1. First item
2. Second item
3. Third item

#### Unordered list

```markdown
- List item
- Another item
- And another item
```

- List item
- Another item
- And another item

#### Nested list

```markdown
- Fruit
  - Apple
  - Orange
  - Banana
- Dairy
  - Milk
  - Cheese
```

Which looks like:

- Fruit
  - Apple
  - Orange
  - Banana
- Dairy
  - Milk
  - Cheese

### HTML elements, like abbr, sub, sup, kbd, mark

You can also write raw HTML within your markdown. This is useful for elements like...

```markdown
<abbr title="Graphics Interchange Format">GIF</abbr> is a bitmap image format.

H<sub>2</sub>O

X<sup>n</sup> + Y<sup>n</sup> = Z<sup>n</sup>

Press <kbd>CTRL</kbd> + <kbd>ALT</kbd> + <kbd>Delete</kbd> to end the session.

Most <mark>salamanders</mark> are nocturnal, and hunt for insects, worms, and other small creatures.
```

Which would output:

<abbr title="Graphics Interchange Format">GIF</abbr> is a bitmap image format.

H<sub>2</sub>O

X<sup>n</sup> + Y<sup>n</sup> = Z<sup>n</sup>

Press <kbd>CTRL</kbd> + <kbd>ALT</kbd> + <kbd>Delete</kbd> to end the session.

Most <mark>salamanders</mark> are nocturnal, and hunt for insects, worms, and other small creatures.


## Other custom components
### Asides / Callouts / Admonitions

Use the `<Aside>` component to highlight important information. It supports four types: `note`, `tip`, `caution`, and `danger`.

```mdx
{/* or type="tip" or "caution" or "danger" */}
<Aside type="note" title="Custom Title">
Your content. You can use **markdown** in here, too.
</Aside>
```

Which will give you...

<Aside type="note" title="Custom Title">
Your content. You can use **markdown** in here, too.
</Aside>

<Aside type="tip">
Your content. You can use **markdown** in here, too.
</Aside>

<Aside type="caution">
Your content. You can use **markdown** in here, too.
</Aside>

<Aside type="danger">
Of course it works with longer content as well. Even things that have multiple elements!

The elements have a gross Tailwind class that manages their margins which makes them tighter in this context. Neat!
</Aside>

### Tabs

Use `<TabsRoot>`, `<TabsList>`, `<Tab>`, and `<TabsPanel>` to show multiple items side-by-side.

<Aside type="note">
- Set `initial` on your first `<Tab>` and first `<TabsPanel>` to make them active by default
- All `<Tab*>` components require `client:idle` — do NOT use `client:visible` because hidden panels won't trigger the Intersection Observer and will never hydrate
- Use descriptive `label` prop on `<TabsList>` for accessibility
</Aside>


````mdx
<TabsRoot client:idle>
  <TabsList client:idle label="Code examples">
    <Tab client:idle value="typescript" initial>TypeScript</Tab>
    <Tab client:idle value="javascript">JavaScript</Tab>
  </TabsList>
  <TabsPanel client:idle value="typescript" initial>
    ```ts
    console.log('Hello, TypeScript!');
    ```
  </TabsPanel>
  <TabsPanel client:idle value="javascript">
    ```js
    console.log('Hello, JavaScript!');
    ```
  </TabsPanel>
</TabsRoot>
````


<TabsRoot client:idle>
  <TabsList client:idle label="Code examples">
    <Tab client:idle value="typescript" initial>TypeScript</Tab>
    <Tab client:idle value="javascript">JavaScript</Tab>
  </TabsList>
  <TabsPanel client:idle value="typescript" initial>
    ```ts
    console.log('Hello, TypeScript!');
    ```
  </TabsPanel>
  <TabsPanel client:idle value="javascript">
    ```js
    console.log('Hello, JavaScript!');
    ```
  </TabsPanel>
</TabsRoot>


### `<ServerCode />`, for showing code from a `{variable}` or `?raw` imported file

While MDX supports inline variables like `{someVariable}`, this doesn't work inside of markdown code blocks.
If you tried
````mdx
```tsx
{someVariable}
```
````
You would just get
```tsx
{someVariable}
```

To work around this, use `<ServerCode />` instead of triple backticks.

<Aside type="caution">
Unlike regular markdown code blocks, `<ServerCode>` does **not** automatically get wrapped in a frame. You should use `TabsRoot` with a single `TabPanel` to make it look pretty
</Aside>

```mdx
import componentCode from '@/examples/react/Component.tsx?raw';
import { TabsRoot, TabsList, TabsPanel, Tab } from '@/components/Tabs';
import ServerCode from '@/components/Code/ServerCode.astro';

<TabsRoot client:idle>
  <TabsList client:idle label="Component implementation">
    <Tab client:idle value="component" initial>Component</Tab>
  </TabsList>
  <TabsPanel client:idle value="component" initial>
    <ServerCode code={componentCode} lang="tsx" />
  </TabsPanel>
</TabsRoot>
```

Which will happily render

<TabsRoot client:idle>
  <TabsList client:idle label="Component implementation">
    <Tab client:idle value="component" initial>Component</Tab>
  </TabsList>
  <TabsPanel client:idle value="component" initial>
    <ServerCode code={`import React from 'react';

function Component() {
  return <div>Hello, world!</div>;
}`} lang="tsx" />
  </TabsPanel>
</TabsRoot>

## Literally any other component

This is just MDX, so you can import any old component and use it. To make that imported component look pretty, you might consider wrapping it in `<MinimalFrame>` or placing it inside of a `<TabsRoot>` alongside code, as shown below.


### `<MinimalFrame>` to limit max width and provide a nice border

Use the `<MinimalFrame>` frame component to wrap standalone demos with a styled border and background:

```mdx
import { MyDemo } from '@/examples/react/MyDemo';
import MinimalFrame from '@/components/frames/Minimal.astro';
<MinimalFrame>
  <MyDemo client:idle />
</MinimalFrame>
```

#### Using `iframe`s in `<MinimalFrame>`

Imo `<MinimalFrame>` is a great tool for laying out `iframe`s. If you go down this path, note that `<MinimalFrame>` has `position: relative;`, which means that you can (and should) absolutely position your `iframe` within it. For example...

```mdx
<MinimalFrame class="aspect-video">
  <iframe class="absolute top-0 left-0 w-full h-full" src="https://jsfiddle.net/ugnkw65y/1/embedded/result,html/light" frameBorder="0" allowFullScreen />
</MinimalFrame>
```

<MinimalFrame class="aspect-video">
  <iframe class="absolute top-0 left-0 w-full h-full" src="https://jsfiddle.net/ugnkw65y/1/embedded/result,html/light" frameBorder="0" allowFullScreen />
</MinimalFrame>

### `<TabsRoot>` supports arbitrary content, too

You can place any old content underneath `<TabsPanel>`, and it'll show alongside whatever tabbed content you're showing. This is a pattern we've used so far to display code alongside a rendered example (e.g., <DocsLink slug="reference/play-button">PlayButton</DocsLink>).

```mdx
import { MyDemo } from '@/examples/react/MyDemo';
import componentCode from '@/examples/react/MyDemo.tsx?raw';
import cssCode from '@/examples/react/MyDemo.module.css?raw';
import { TabsRoot, TabsList, TabsPanel, Tab } from '@/components/Tabs';
import ServerCode from '@/components/Code/ServerCode.astro';

<TabsRoot client:idle>
  <TabsList client:idle label="MyDemo implementation">
    <Tab client:idle value="component" initial>Component</Tab>
    <Tab client:idle value="css">CSS Module</Tab>
  </TabsList>
  <TabsPanel client:idle value="component" initial>
    <ServerCode code={componentCode} lang="tsx" />
  </TabsPanel>
  <TabsPanel client:idle value="css">
    <ServerCode code={cssCode} lang="css" />
  </TabsPanel>
  <MyDemo client:idle />
</TabsRoot>
```
