@pvvng/react-typing-text
Version:
A lightweight and fully customizable typing animation component for React.
118 lines (89 loc) • 7.35 kB
Markdown
# React Typing Text
React component for typing animation with full control – pause, resume, loop, custom cursor, and more.
[](https://www.npmjs.com/package/@pvvng/react-typing-text)
[](https://pvvng.github.io/react-typing-text)
## Install
```bash
npm install @pvvng/react-typing-text
```
## Storybook
Try it live on Storybook -> [Link](https://pvvng.github.io/react-typing-text/?path=/docs/examples-typingtextexample--docs)
## Simple Example
```tsx
import { useRef } from "react";
import { TypingText, TypingTextHandle } from "@pvvng/react-typing-text";
export default function Example() {
const typingRef = useRef<TypingTextHandle>(null);
return (
<>
<TypingText
ref={typingRef}
text="Hello, world!"
interval={100}
loop
startDelay={500}
onTypingStart={() => console.log("Typing started")}
onType={(char, idx) => console.log(`Typed ${char} at ${idx}`)}
onTypingEnd={() => console.log("Typing ended")}
/>
<button onClick={() => typingRef.current?.pause()}>Pause</button>
<button onClick={() => typingRef.current?.resume()}>Resume</button>
<button onClick={() => typingRef.current?.reset()}>Reset</button>
</>
);
}
```
## Typing Text Options
> Props marked with `*` are **required**.
| Prop | Type | Default | Description |
| --------------- | --------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `text*` | `string` | — | The text string to animate with typing effect. |
| `autoScroll` | `boolean` | `true` | Whether to automatically scroll to the end as typing progresses. |
| `startDelay` | `number` | `0` | Delay in milliseconds before typing starts. Applied every time the `text` prop changes, including initial mount. |
| `interval` | `number` | `60` | Interval in milliseconds between typing each character. |
| `loop` | `boolean` | `false` | Whether to loop the typing animation continuously. |
| `loopDelay` | `number` | `1000` | Delay in milliseconds before restarting the looped typing animation. |
| `className` | `string` | — | CSS class name applied to the container element. |
| `style` | `React.CSSProperties` | — | Inline styles applied to the container element. |
| `cursor` | `React.ReactElement<"span"> \| null` | — | Custom cursor element. Must be a `<span>` (or other inline element) to avoid invalid HTML structure and hydration errors. Set `null` to disable the cursor completely. |
| `onTypingStart` | `() => void` | — | Callback fired once when typing starts after `startDelay`. |
| `onType` | `(char: string, index: number) => void` | — | Callback fired on each typed character with the character and its index. |
| `onTypingEnd` | `() => void` | — | Callback fired once when typing finishes (or after the last loop iteration). |
### Usage tips:
- startDelay is applied only once when the text prop changes (initial mount or text update), and not on subsequent loops.
- The onTypingStart and onTypingEnd callbacks are called on every typing start and end cycle, including loops.
- Use loop and loopDelay to control repeated typing animations.
- Set cursor={null} to completely disable the cursor display.
## TypingTextHandle Method
Accessible via `ref` using `useRef<TypingTextHandle>()`.
| Method | Description |
| -------- | --------------------------------------------------------------------- |
| `pause` | Pauses the typing animation. |
| `resume` | Resumes the typing animation if paused and not finished. |
| `reset` | Resets the typing animation to the start and resumes typing. |
| `skip()` | **Skips** the current typing and immediately renders the full `text`. |
> Use `skip()` to let users instantly reveal all text without waiting for the animation.
### Usage tips:
- Use the ref returned by useRef<TypingTextHandle>() to call these methods imperatively.
- pause and resume help control flow for advanced UIs (e.g., pausing when a modal opens).
- reset can be tied to events like changing the text prop or user-triggered replay.
## Default Cursor
If you do not provide a custom `cursor` prop, the component will render a default blinking cursor as a `<span>` element with the following styles:
- `display: inline-block`
- `vertical-align: middle`
- `width: 2px`
- `height: 1rem`
- `background-color: black`
- `margin-left: 4px`
- blinking animation
This default cursor is designed to visually resemble a typical text caret and supports **auto-scrolling** behavior when `autoScroll` is enabled.
> **Important:**
>
> In HTML, a `<p>` element **cannot contain** block-level elements like `<div>` or nested `<p>`.
>
> For example, placing a `<div>` inside a `<p>` will cause **hydration errors** such as:
> `"In HTML, <div> cannot be a descendant of <p>. This will cause a hydration error. <p> cannot contain a nested <div>."`
>
> To prevent these errors, the `cursor` prop **must be a `<span>` element** (or other inline elements) because the typing text and cursor are wrapped inside a `<p>`.
> Using a `<span>` ensures valid HTML structure and avoids rendering/hydration issues.
If you want to disable the cursor completely, set the `cursor` prop to `null`.