# <motion-code>

Syntax-highlighted code block with macOS-style window chrome, an optional copy
button, and an optional typewriter reveal. Highlighting is built in for HTML,
JS/TS, CSS, JSON and Python, with no external tokenizer; token colours are
overridable through CSS custom properties.

Source is read from a `<script type="text/plain">` child, a `<pre>` child
(which keeps the code in the page HTML for search engines), or the text of
child `<div>` elements, one per line. Either way the result is dedented.

**Use it for:** code examples in docs, blog posts and landing pages that
need a file name, a copy button, or a typing effect for a short snippet.

**Avoid it for:** code inside a sentence; use `motion-code-inline`.
Languages other than HTML, JS/TS, CSS, JSON and Python show as plain text.
Avoid `typing` on long code that people need to read or copy at once.

**Accessibility:** the code is real text in a `<pre>`, so screen readers
can read it and people can select it. The copy button is a native
`<button>` named "Copy", which changes to "Copied" for 1.8 seconds after a
click, without a live region. With `typing`, the readable `<pre>` holds only
the characters typed so far (the full copy is `aria-hidden`), and with the
default `typing-loop` it empties again on every pass. Set
`typing-loop="false"` so the full code stays after one pass.

**Reduced motion:** the full code shows at once, with no typing, no loop
and no blinking cursor.

**Common mistakes:** putting the code as plain text directly inside the
element: only a `<script type="text/plain">`, a `<pre>` or child `<div>`
elements are read, so nothing shows. Setting `copy` together with
`hide-chrome`: the copy button is in the title bar, so it is hidden too.

Docs: https://www.motion-components.dev/docs/code/motion-code/

## Install

```js
import 'motion-components/motion-code'
```

Or without a build step:

```html
<script type="module" src="https://cdn.jsdelivr.net/npm/motion-components@1/dist/motion-code.js/+esm"></script>
```

## Example

```html
<motion-code filename="app.ts" copy copy-label typing typing-speed="60" typing-loop="false">
  <script type="text/plain">
    const greeting = 'hello'
  </script>
</motion-code>
```

## Attributes

| Attribute | Type | Default | Description |
| --- | --- | --- | --- |
| `filename` | `string` | `'app.html'` | Name shown in the window chrome. Doubles as the language hint: the file extension picks the tokenizer unless `code-lang` overrides it. |
| `code-lang` | `string` | `''` | Explicit highlighting language, overriding the `filename` extension. One of `html`, `js`, `css`, `json` or `python`; anything else renders unhighlighted. |
| `hide-chrome` | `boolean` | `false` | Hide the whole title bar: traffic-light dots, filename and copy button. Suppresses `copy` as a side effect, since the button lives in the chrome. |
| `copy` | `boolean` | `false` | Show a copy-to-clipboard button in the chrome. Copies the dedented source, not the highlighted markup. |
| `copy-label` | `boolean` | `false` | Label the copy button with "Copy" / "Copied!" text instead of showing the icon alone. |
| `compact` | `boolean` | `false` | Denser layout: smaller radius, tighter padding and a smaller type scale. |
| `typing` | `boolean` | `false` | Reveal the code with a typewriter animation instead of rendering it at once. |
| `typing-speed` | `number` | `80` | Typing speed in characters per second. Total duration is derived from the character count. |
| `typing-delay` | `number` | `0` | Delay in seconds before the first character appears, applied on every pass. |
| `typing-loop` | `boolean` | `true` | Repeat the typing animation. Set `typing-loop="false"` to type once; the animation then waits until the block scrolls into view instead of starting on connect. |
| `typing-hold` | `number` | `1.5` | Seconds to hold the completed text before restarting. Ignored when `typing-loop="false"`. |

## Properties

| Property | Type | Description |
| --- | --- | --- |
| `code` | `string` | The source shown, before highlighting. Setting it is the same as `setCode()`. |
| `playState` | `'idle' \| 'running' \| 'paused' \| 'finished'` | Current state: `'idle'`, `'running'`, `'paused'` or `'finished'`. |
| `finished` | `Promise<void>` | Resolves when the current run settles. A new run replaces the promise. |

## Methods

| Method | Description |
| --- | --- |
| `replay()` | Restart the typing animation from the beginning |
| `setCode()` | Replaces the code. A typing run in progress is cancelled with `motion-cancel`, and typing starts again. |
| `play()` | Starts the animation, or resumes it when paused. Resolves once the run settles. Under `prefers-reduced-motion: reduce` the final state is applied immediately without animating. |
| `pause()` | Holds the animation at its current position. No-op unless running. |
| `finish()` | Jumps to the final state and settles. Fires `motion-finish`. |
| `cancel()` | Reverts to the initial state and returns to idle. Fires `motion-cancel`. |

## Events

The `motion-*` events bubble and are composed.

| Event | Description |
| --- | --- |
| `motion-start` | When a run starts. |
| `motion-finish` | When a run finishes, or `finish()` jumps to the end. |
| `motion-cancel` | When `cancel()` stops a run and resets it. |

## CSS custom properties

| Property | Description |
| --- | --- |
| `--mc-code-keyword` | Keyword token colour. |
| `--mc-code-string` | String token colour. |
| `--mc-code-tag` | Tag and selector token colour. |
| `--mc-code-attr` | Attribute and property token colour. |
| `--mc-code-num` | Numeric token colour. |
| `--mc-code-comment` | Comment token colour. Falls back to `--mc-color-muted`. |
| `--mc-color-surface` | Background of the code area. |
| `--mc-color-surface-2` | Background of the window and its title bar. |
| `--mc-color-border` | Window border, title bar divider and copy button border. |
| `--mc-color-muted` | File name, copy button and typing cursor color. |
| `--mc-color-accent` | Copy button color on hover. |
