Looking forward to your feedback
A typewriter utility for the browser. It builds a queue of actions so you can chain type, pause, delete, move, add, image, and then run them with go().
- Chained typing actions powered by the Web Animations API cursor
- Customizable typing speed, start delay, and cursor animation
- Supports plain text typing as well as inserting HTML elements and images
- Optional per-element animations when inserting DOM nodes
- Works with any DOM element
npm install untyperimport { UnTyper } from 'untyper'
const target = document.querySelector('#text')
const typer = new UnTyper(target, {
speed: 90,
startDelay: 300,
cursorAnimation: {
kind: 'combined',
duration: 900,
},
})
await typer
.type('Hi there!')
.pause(400)
.delete(6)
.type('untyper!')
.go()| Option | Type | Default | Description |
|---|---|---|---|
speed |
number |
120 |
Base delay between characters (ms). |
startDelay |
number |
0 |
Delay before the queue starts (ms). |
animationspancontent |
string |
` | ` |
animate.cancel |
boolean |
false |
Hide cursor after the queue completes. |
cursorAnimation |
CursorAnimationOptions |
— | Cursor animation customization. |
plugins |
UnTyperPluginUse[] |
[] |
Plugins installed when the instance is created. |
Adds a plain text typing action. HTML is not supported here.
text:stringoptions.delay: optional delay (ms) after typing this text
Returns this.
Adds a pause action.
ms:number
Returns this.
Deletes characters from the current cursor position.
charCount:number(must be greater than 0)options.delay: optional delay (ms) after deleting
Returns this.
Moves the cursor.
movementArg:number | null- Provide a negative number to move left by that many characters.
- Use
nullwithoptions.to = 'start' | 'end'to jump to the start or end.
Returns this.
Parses HTML and inserts elements with typing animation for text nodes. You can pass options.animation to animate inserted elements.
html:stringoptions.delay: optional delay (ms) after addingoptions.animation: optionalElementAnimationto apply to added elements
Returns this.
Inserts an img element with optional attributes. You can also pass options.animation to animate the image after insertion.
src:stringoptions.alt:stringoptions.className:stringoptions.width:numberoptions.height:numberoptions.attrs:Record<string, string>for additional attributesoptions.delay: optional delay (ms) after insertingoptions.animation: optionalElementAnimationto apply to the image
Returns this.
Installs a plugin after the instance is created. A plugin can be a function or an object with name and install(ctx, options).
Returns this.
Registers a chainable custom action.
Returns this.
Runs a custom action registered by a plugin or by registerAction.
Returns this.
Runs the queued actions.
Returns Promise<void>.
You can apply custom animations to inserted DOM elements using options.animation on add or image.
await typer
.add('<strong>Spotlight</strong>', {
animation: {
keyframes: [
{ opacity: 0, transform: 'translateY(4px)' },
{ opacity: 1, transform: 'translateY(0)' },
],
options: { duration: 300, easing: 'ease-out' },
},
})
.image('/logo.png', {
alt: 'Brand logo',
animation: {
keyframes: [
{ transform: 'scale(0.9)', opacity: 0 },
{ transform: 'scale(1)', opacity: 1 },
],
options: { duration: 250 },
},
})
.go()Plugins follow the common frontend plugin shape: expose a stable install(ctx, options) entrypoint, keep setup side effects inside install, and register extension points through the provided context instead of reaching into private fields.
import type { UnTyperPlugin } from 'untyper'
const emojiPlugin: UnTyperPlugin<{ suffix?: string }> = {
name: 'emoji',
install(ctx, options) {
ctx.registerAction('emoji', (api, text: string) => {
api.insertText(`${text}${options?.suffix ?? ''}`)
})
ctx.hook('afterRun', ({ root }) => {
root.setAttribute('data-untyper-complete', 'true')
})
},
}
await new UnTyper(target, {
speed: 80,
plugins: [[emojiPlugin, { suffix: '!' }]],
})
.type('Status: ')
.action('emoji', 'ready')
.go()Plugin context:
| API | Description |
|---|---|
ctx.registerAction(name, handler) |
Adds a named custom action that can be called with action(name, ...args). |
ctx.enqueue(steps, options) |
Adds raw queue steps for advanced plugins. Queue func handlers may be async. |
ctx.insertText(text, options) |
Reuses the built-in text typing behavior. |
ctx.insertElement(element, options) |
Reuses the built-in DOM insertion behavior. |
ctx.hook(name, handler) |
Registers lifecycle hooks: beforeRun, afterRun, beforeStep, afterStep, onError. |
ctx.root, ctx.cursor, ctx.options |
Read-only access to the target element, cursor, and resolved options. |
