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 libraryUsage
<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
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.
<!-- 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 |
|---|---|---|---|---|
| | | string | "app.html" | Shown in the chrome bar; also used to infer the language |
| | | string | "" | Override language: html · js · css · json · python · sh |
| | | boolean | false | Show a copy icon button in the chrome bar |
| | | boolean | false | Show a "Copy" text label next to the copy icon |
| | | boolean | false | Remove the title bar entirely |
| | | boolean | false | Reduce padding, font size, border radius, and title bar height |
| | | boolean | false | Animate code in character by character with a blinking cursor. Loops automatically. |
| | | number | 80 | Typing speed in characters per second |
| | | number | 0 | Seconds to wait before typing starts, on every pass |
| | | boolean | true | Repeat the typing. Set |
| | | number | 1.5 | Seconds to hold the finished code before typing it again |
| | | string | "" | Property only: reads or replaces the source, before highlighting. Same as |
CSS variables
| Variable | Type | Default | Description |
|---|---|---|---|
| | color | #7c3aed | Keywords, booleans, null |
| | color | #16a34a | String literals |
| | color | #0369a1 | HTML tags, CSS selectors |
| | color | #be123c | Attributes, CSS properties, JSON keys, decorators |
| | color | #b45309 | Numbers and units |
| | color | var(--mc-color-muted) | Comments |
| | color | #ffffff | Background of the code area |
| | color | #f0f0f8 | Background of the window and its title bar |
| | color | #dddde8 | Window border, title bar divider and copy button border |
| | color | #60608a | File name, copy button and typing cursor |
| | color | #2563eb | Copy button on hover |
Methods
| Method | Type | Default | Description |
|---|---|---|---|
| | void | — | Replace the code. A typing run in progress is cancelled with |
| | 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 finished state.
const card = document.querySelector(".card")
animate(card, {
scale: [0.95, 1],
opacity: [0, 1],
}, { duration: 0.4 })Accessibility
Respects prefers-reduced-motion: when enabled, the full code shows at once with no typing, and the cursor does not blink.