motion-code

A syntax-highlighted code block with a macOS-style chrome, built-in tokenizer for multiple languages, typing animation, and compact mode.

Preview

import { animate, stagger } from "motion"

animate(".card", {
  y: [24, 0],
  opacity: [0, 1],
}, {
  duration: 0.5,
  delay: stagger(0.08),
})

Import

import 'motion-components/motion-code'   // just this one
import 'motion-components'               // or the whole library

Usage

<motion-code filename="app.ts">
  <script type="text/plain">
    import { animate } from "motion"
    animate(".box", { opacity: [0, 1] }, { duration: 0.5 })
  </script>
</motion-code>

Copy button

Add copy to show a copy icon button in the chrome bar. It's the same icon used in motion-code-inline. Add copy-label to show a "Copy" text label next to the icon.

animate(".box", { opacity: [0, 1] }, { duration: 0.5 })
<!-- Icon only -->
<motion-code filename="app.ts" copy>...</motion-code>

<!-- Icon + "Copy" label -->
<motion-code filename="app.ts" copy copy-label>...</motion-code>

Typing animation

Add typing to animate code appearing character by character. Syntax highlighting applies as it types. It loops by default. Control the speed with typing-speed (characters per second, default 80) and the pause between loops with typing-hold (seconds).

const card = document.querySelector(".card")

animate(card, {
  scale: [0.95, 1],
  opacity: [0, 1],
}, { duration: 0.4 })
<motion-code filename="app.ts" typing typing-speed="65">
  <script type="text/plain">
    animate(".card", { opacity: [0, 1] })
  </script>
</motion-code>

On reveal: type once

Set typing-loop="false" to type once. The animation then plays when the element scrolls into view instead of starting immediately.

animate(".hero", {
  opacity: [0, 1],
  y: [20, 0],
}, { duration: 0.5 })
<motion-code filename="app.ts" typing typing-loop="false">
  ...
</motion-code>

Delayed typing

Use typing-delay (seconds) to wait before typing starts. This is useful when the window animates into view.

from motion import animate

animate(".hero", {
    "opacity": [0, 1],
    "y": [20, 0],
}, duration=0.5)
<motion-code filename="app.py" typing typing-speed="55" typing-delay="0.5">
  ...
</motion-code>

Compact

Add compact for tighter padding, smaller font, and a slimmer title bar. Useful inside cards or sidebars.

{
  "name": "motion-components",
  "version": "0.1.0",
  "type": "module"
}
<motion-code filename="config.json" compact>
  ...
</motion-code>

Hide chrome

Use hide-chrome to remove the title bar entirely, leaving just the code body.

npm install motion-components
<motion-code hide-chrome>
  <script type="text/plain">
    npm install motion-components
  </script>
</motion-code>

Languages

Language is inferred from the filename extension. Override with the lang attribute.

HTML / AstroJavaScript / TypeScriptCSSJSONPythonShell
<!-- Auto-detected from extension -->
<motion-code filename="styles.css">...</motion-code>
<motion-code filename="data.json">...</motion-code>
<motion-code filename="script.py">...</motion-code>

<!-- Override manually -->
<motion-code code-lang="js">...</motion-code>

Theming

Token colours are CSS custom properties that pierce the Shadow DOM. Map any external theme's palette to these variables on :root.

/* VS Code Dark+ */
:root {
  --mc-code-keyword: #569cd6;
  --mc-code-string:  #ce9178;
  --mc-code-tag:     #4ec9b0;
  --mc-code-attr:    #9cdcfe;
  --mc-code-num:     #b5cea8;
  --mc-code-comment: #6a9955;
}

Properties

Attribute Property Type Default Description
filename filename string "app.html" Shown in the chrome bar; also used to infer the language
code-lang codeLang string "" Override language: html · js · css · json · python · sh
copy copy boolean false Show a copy icon button in the chrome bar
copy-label copyLabel boolean false Show a "Copy" text label next to the copy icon
hide-chrome hideChrome boolean false Remove the title bar entirely
compact compact boolean false Reduce padding, font size, border radius, and title bar height
typing typing boolean false Animate code in character by character with a blinking cursor. Loops automatically.
typing-speed typingSpeed number 80 Typing speed in characters per second
typing-delay typingDelay number 0 Seconds to wait before typing starts, on every pass
typing-loop typingLoop boolean true Repeat the typing. Set typing-loop="false" to type once when the block scrolls into view
typing-hold typingHold number 1.5 Seconds to hold the finished code before typing it again
code code string "" Property only: reads or replaces the source, before highlighting. Same as setCode(), and it works when set before the element is connected

CSS variables

Variable Type Default Description
--mc-code-keyword color #7c3aed Keywords, booleans, null
--mc-code-string color #16a34a String literals
--mc-code-tag color #0369a1 HTML tags, CSS selectors
--mc-code-attr color #be123c Attributes, CSS properties, JSON keys, decorators
--mc-code-num color #b45309 Numbers and units
--mc-code-comment color var(--mc-color-muted) Comments
--mc-color-surface color #ffffff Background of the code area
--mc-color-surface-2 color #f0f0f8 Background of the window and its title bar
--mc-color-border color #dddde8 Window border, title bar divider and copy button border
--mc-color-muted color #60608a File name, copy button and typing cursor
--mc-color-accent color #2563eb Copy button on hover

Methods

Method Type Default Description
setCode(raw) void — Replace the code. A typing run in progress is cancelled with motion-cancel, and typing starts again if typing is enabled.
replay() void — Restart the typing animation from the beginning.

JavaScript API

Every playback verb drives the typing animation: play(), pause(), finish() (snap to the fully-typed code), and cancel() (clear the window). replay() is shorthand for cancel() + play(). This instance uses typing-loop="false", so a completed run settles into the finished state.

const card = document.querySelector(".card")

animate(card, {
  scale: [0.95, 1],
  opacity: [0, 1],
}, { duration: 0.4 })
playState: –

Accessibility

Respects prefers-reduced-motion: when enabled, the full code shows at once with no typing, and the cursor does not blink.