typewriterTypewriter
打字机English definition
A text sequence reveals characters at timed intervals to simulate incremental entry.
Chinese translation
文字像正在输入一样逐字符出现。
typewriterReveal short text character by character while preserving complete accessible text.
A text sequence reveals characters at timed intervals to simulate incremental entry.
Motion, made legible.
Implement Typewriter: Reveal short text character by character while preserving complete accessible text. Use Demo duration 1200ms, Characters 18, Show caret on. Trigger it once when state changes and keep it replayable. Use semantic HTML, scope CSS to .motion-demo--typewriter. Provide equivalent low-motion behavior for prefers-reduced-motion and .force-reduced-motion.
<div class="motion-demo motion-demo--typewriter" data-motion="typewriter" aria-label="Typewriter demo">
<p class="motion-typewriter" aria-label="Motion, made legible.">Motion, made legible.</p>
</div>.motion-demo.motion-demo--typewriter {
box-sizing: border-box;
position: relative;
display: grid;
place-items: center;
width: min(100%, 34rem);
min-height: 15rem;
padding: 2rem;
overflow: hidden;
color: #18181b;
background: #fafafa;
border: 1px solid #e4e4e7;
border-radius: 16px;
isolation: isolate;
}
.motion-demo.motion-demo--typewriter *, .motion-demo.motion-demo--typewriter *::before, .motion-demo.motion-demo--typewriter *::after {
box-sizing: border-box;
}
.motion-demo.motion-demo--typewriter .motion-surface {
position: relative;
display: grid;
gap: 0.65rem;
width: min(100%, 18rem);
padding: 1.25rem;
background: #ffffff;
border: 1px solid #e4e4e7;
border-radius: 16px;
box-shadow: none;
}
.motion-demo.motion-demo--typewriter .motion-surface strong { font-weight: 500; }
.motion-demo.motion-demo--typewriter .motion-line {
display: block;
width: 100%;
height: 0.5rem;
background: #e4e4e7;
border-radius: 999px;
}
.motion-demo.motion-demo--typewriter .motion-line:last-child { width: 62%; }
.motion-demo.motion-demo--typewriter .motion-button {
position: relative;
min-height: 2.75rem;
padding: 0.75rem 1.1rem;
color: white;
font: inherit;
font-weight: 700;
background: #18181b;
border: 0;
border-radius: 999px;
cursor: pointer;
}
.motion-demo.motion-demo--typewriter .motion-button:focus-visible { outline: 3px solid rgb(37 99 235 / 32%); outline-offset: 3px; }
.motion-demo.motion-demo--typewriter .motion-action-row {
display: flex;
justify-content: center;
gap: 0.5rem;
margin-top: 0.85rem;
}
.motion-demo.motion-demo--typewriter .motion-replay-scene {
width: min(100%, 22rem);
display: grid;
place-items: center;
}
.motion-demo.motion-demo--typewriter .motion-pausable-scene {
width: min(100%, 22rem);
display: grid;
place-items: center;
}
.motion-demo.motion-demo--typewriter button.motion-surface {
color: inherit;
font: inherit;
text-align: start;
cursor: pointer;
}
.motion-demo.motion-demo--typewriter .motion-replay-button,
.motion-demo.motion-demo--typewriter .motion-undo-button,
.motion-demo.motion-demo--typewriter .motion-dismiss-button,
.motion-demo.motion-demo--typewriter .motion-pause-button {
min-height: 2.75rem;
padding: 0.65rem 0.9rem;
color: #18181b;
font: 650 0.78rem/1 ui-sans-serif, system-ui, sans-serif;
background: #ffffff;
border: 1px solid #d4d4d8;
border-radius: 8px;
cursor: pointer;
}
.motion-demo.motion-demo--typewriter .motion-replay-button:focus-visible,
.motion-demo.motion-demo--typewriter .motion-undo-button:focus-visible,
.motion-demo.motion-demo--typewriter .motion-dismiss-button:focus-visible,
.motion-demo.motion-demo--typewriter .motion-pause-button:focus-visible,
.motion-demo.motion-demo--typewriter [data-reorder-item]:focus-visible,
.motion-demo.motion-demo--typewriter [data-swipe-target]:focus-visible {
outline: 3px solid rgb(37 99 235 / 32%);
outline-offset: 3px;
}
.motion-demo.motion-demo--typewriter .motion-status {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.motion-demo.motion-demo--typewriter .motion-ripple-ink {
position: absolute;
width: 12px;
height: 12px;
pointer-events: none;
background: rgb(255 255 255 / 72%);
border-radius: 50%;
transform: translate(-50%, -50%) scale(0.95);
opacity: 0;
}
.motion-demo.motion-demo--typewriter .motion-state-stack { position: relative; width: min(100%, 18rem); height: 9rem; }
.motion-demo.motion-demo--typewriter .motion-state { position: absolute; inset: 0; display: grid; place-items: center; padding: 1rem; background: #ffffff; border: 1px solid #e4e4e7; border-radius: 16px; }
.motion-demo.motion-demo--typewriter .motion-state--to { background: #18181b; color: white; }
.motion-demo.motion-demo--typewriter .motion-scroll-track > span { color: #71717a; font: 600 0.72rem/1.2 ui-monospace, monospace; letter-spacing: 0.08em; text-transform: uppercase; }
.motion-demo.motion-demo--typewriter .motion-orbit-item { display: grid; place-items: center; width: 2.5rem; height: 2.5rem; color: white; background: #2563eb; border-radius: 50%; }
.motion-demo.motion-demo--typewriter .motion-text-stack { position: relative; width: min(100%, 18rem); min-height: 4rem; }
.motion-demo.motion-demo--typewriter svg { width: min(100%, 20rem); height: auto; }
.motion-demo.motion-demo--typewriter .motion-typewriter { position: relative; max-width: 18ch; overflow: hidden; white-space: nowrap; font: 650 1.4rem/1.4 ui-monospace, monospace; animation: motion-typewriter 1200ms steps(18, end) both; }
.motion-demo.motion-demo--typewriter .motion-typewriter::after { content: ""; display: inline-block; width: 2px; height: 1em; margin-left: 0.08em; vertical-align: -0.12em; background: #2563eb; animation: motion-typewriter-caret 700ms step-end infinite; }
@keyframes motion-typewriter { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0); } }
@keyframes motion-typewriter-caret { 50% { opacity: 0; } }
@keyframes motion-typewriter-reduced-fade {
from { opacity: 0.84; }
to { opacity: 1; }
}
.force-reduced-motion .motion-demo.motion-demo--typewriter {
animation: motion-typewriter-reduced-fade 160ms cubic-bezier(0.23, 1, 0.32, 1) both !important;
}
.force-reduced-motion .motion-demo.motion-demo--typewriter *,
.force-reduced-motion .motion-demo.motion-demo--typewriter *::before,
.force-reduced-motion .motion-demo.motion-demo--typewriter *::after {
animation: none !important;
animation-delay: 0ms !important;
animation-iteration-count: 1 !important;
transition-property: opacity, color, background-color, border-color !important;
transition-duration: 160ms !important;
transition-delay: 0ms !important;
scroll-behavior: auto !important;
}
.force-reduced-motion .motion-demo.motion-demo--typewriter .motion-button,
.force-reduced-motion .motion-demo.motion-demo--typewriter [data-reorder-item],
.force-reduced-motion .motion-demo.motion-demo--typewriter [data-swipe-target],
.force-reduced-motion .motion-demo.motion-demo--typewriter [data-spring-target] {
transform: none !important;
}
.force-reduced-motion .motion-demo.motion-demo--typewriter .motion-path { stroke-dashoffset: 0 !important; }
.force-reduced-motion .motion-demo.motion-demo--typewriter .motion-word--from { opacity: 0 !important; visibility: hidden; }
.force-reduced-motion .motion-demo.motion-demo--typewriter .motion-word:not(.motion-word--from) { opacity: 1 !important; filter: none !important; transform: none !important; }
@media (prefers-reduced-motion: reduce) {
.motion-demo.motion-demo--typewriter {
animation: motion-typewriter-reduced-fade 160ms cubic-bezier(0.23, 1, 0.32, 1) both !important;
}
.motion-demo.motion-demo--typewriter *, .motion-demo.motion-demo--typewriter *::before, .motion-demo.motion-demo--typewriter *::after {
animation: none !important;
animation-delay: 0ms !important;
animation-iteration-count: 1 !important;
transition-property: opacity, color, background-color, border-color !important;
transition-duration: 160ms !important;
transition-delay: 0ms !important;
scroll-behavior: auto !important;
}
.motion-demo.motion-demo--typewriter .motion-button,
.motion-demo.motion-demo--typewriter [data-reorder-item],
.motion-demo.motion-demo--typewriter [data-swipe-target],
.motion-demo.motion-demo--typewriter [data-spring-target] {
transform: none !important;
}
.motion-demo.motion-demo--typewriter .motion-path { stroke-dashoffset: 0 !important; }
.motion-demo.motion-demo--typewriter .motion-word--from { opacity: 0 !important; visibility: hidden; }
.motion-demo.motion-demo--typewriter .motion-word:not(.motion-word--from) { opacity: 1 !important; filter: none !important; transform: none !important; }
}typewriterA text sequence reveals characters at timed intervals to simulate incremental entry.
文字像正在输入一样逐字符出现。
Show the complete text immediately and keep a static caret or remove caret blinking.
| Parameter | Range / options | Default | Purpose |
|---|---|---|---|
duration | 600ms–4000ms | 1200ms | Uses a longer demo duration so the full change stays observable; immediate production UI feedback should stay under 300ms. |
characters | 6–36 | 18 | Adjusts characters. |
caret | On / Off | On | Shows a blinking text caret. |