{"id":28628227,"url":"https://github.com/react18-tools/typingfx","last_synced_at":"2025-06-12T10:11:48.223Z","repository":{"id":291048858,"uuid":"974012387","full_name":"react18-tools/typingfx","owner":"react18-tools","description":"TypingFX: Bring your text to life, one keystroke at a time.","archived":false,"fork":false,"pushed_at":"2025-05-29T03:08:23.000Z","size":619,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-29T04:20:24.224Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/react18-tools.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"contributing.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["react18-tools","mayank1513"],"polar":"mayank1513","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":["https://pages.razorpay.com/mayank1513"]}},"created_at":"2025-04-28T06:04:48.000Z","updated_at":"2025-05-29T03:07:58.000Z","dependencies_parsed_at":"2025-05-02T05:35:20.288Z","dependency_job_id":null,"html_url":"https://github.com/react18-tools/typingfx","commit_stats":null,"previous_names":["react18-tools/typingfx"],"tags_count":4,"template":false,"template_full_name":"react18-tools/turborepo-template","purl":"pkg:github/react18-tools/typingfx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/react18-tools%2Ftypingfx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/react18-tools%2Ftypingfx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/react18-tools%2Ftypingfx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/react18-tools%2Ftypingfx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/react18-tools","download_url":"https://codeload.github.com/react18-tools/typingfx/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/react18-tools%2Ftypingfx/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259444983,"owners_count":22858553,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-12T10:11:47.513Z","updated_at":"2025-06-12T10:11:48.195Z","avatar_url":"https://github.com/react18-tools.png","language":"TypeScript","funding_links":["https://github.com/sponsors/react18-tools","https://github.com/sponsors/mayank1513","https://polar.sh/mayank1513","https://pages.razorpay.com/mayank1513"],"categories":[],"sub_categories":[],"readme":"# TypingFX \u003cimg src=\"https://raw.githubusercontent.com/mayank1513/mayank1513/main/popper.png\" style=\"height: 40px\"/\u003e\n\n[![test](https://github.com/react18-tools/typingfx/actions/workflows/test.yml/badge.svg)](https://github.com/react18-tools/typingfx/actions/workflows/test.yml) [![Maintainability](https://api.codeclimate.com/v1/badges/aa896ec14c570f3bb274/maintainability)](https://codeclimate.com/github/react18-tools/typingfx/maintainability) [![codecov](https://codecov.io/gh/react18-tools/typingfx/graph/badge.svg)](https://codecov.io/gh/react18-tools/typingfx) [![Version](https://img.shields.io/npm/v/typingfx.svg?colorB=green)](https://www.npmjs.com/package/typingfx) [![Downloads](https://img.jsdelivr.com/img.shields.io/npm/d18m/typingfx.svg)](https://www.npmjs.com/package/typingfx) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/typingfx) [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/from-referrer/)\n\n\u003e **⚡ Customizable, smooth, and snappy typing animations for React**  \n\u003e Animate your text like a pro — fully compatible with React 18/19, Next.js 14/15, and React Server Components.\n\n---\n\n## ✨ Features\n\n- 🎯 Built for modern React (18/19) and Next.js (14/15)\n- ✨ Smooth, realistic word-by-word animation\n- 🔁 Step-based sequences with infinite looping\n- 💅 JSX-ready — animate styled, rich text effortlessly\n- 🧠 Honors `prefers-reduced-motion` accessibility setting\n- ⚡ Hybrid CSS + JS for best performance\n- 💡 Fully typed with TypeScript\n- 🧩 SSR-safe and RSC-compatible\n- 🚫 No runtime dependencies\n\n---\n\n## 🚀 Install\n\n```bash\npnpm add typingfx\n```\n\n**_or_**\n\n```bash\nnpm install typingfx\n```\n\n**_or_**\n\n```bash\nyarn add typingfx\n```\n\n---\n\n## 🔧 Usage\n\n### ① Import Styles\n\n\u003e 🎨 Required for typing animation and cursor styling.\n\n**In JSX (Next.js layout files recommended):**\n\n```tsx\nimport \"typingfx/dist/index.css\";\n```\n\n**Or in global CSS:**\n\n```css\n@import \"typingfx/dist/index.css\";\n```\n\n---\n\n### ② Basic Typing Animation\n\n```tsx\nimport { TypeOut } from \"typingfx\";\n\nexport default function Example() {\n  return (\n    \u003cTypeOut\n      steps={[\"Frontend Developer.\", \"React Enthusiast.\", \"Open Source Advocate.\"]}\n      speed={25}\n      delSpeed={40}\n      repeat={Infinity}\n    /\u003e\n  );\n}\n```\n\n---\n\n### ③ Single-Step Typing\n\nNeed a one-off typing effect without using `steps`?\n\n```tsx\nexport default function Example() {\n  return (\n    \u003cTypeOut\u003e\n      I love {500} \u003cstrong\u003etypingfx\u003c/strong\u003e\n    \u003c/TypeOut\u003e\n  );\n}\n```\n\n\u003e ⏱️ Use numbers inside JSX to insert pauses (in milliseconds) during typing.  \n\u003e ➖ Negative numbers delay deletion.  \n\u003e 🔤 Want to render the number instead? Wrap it with `String()` or use template literals.\n\n---\n\n### ④ Animate JSX \u0026 Rich Text\n\n```tsx\n\u003cTypeOut\n  steps={[\n    \u003c\u003e\n      Building with \u003cstrong\u003eReact\u003c/strong\u003e\n    \u003c/\u003e,\n    \u003c\u003e\n      Deploying on \u003ccode\u003eVercel\u003c/code\u003e\n    \u003c/\u003e,\n    \u003c\u003e\n      Coding like a \u003cspan className=\"emoji\"\u003e💻\u003c/span\u003e\n    \u003c/\u003e,\n  ]}\n  speed={30}\n  repeat={3}\n/\u003e\n```\n\n---\n\n## 🧪 Component Animation (Beta)\n\nTypingFX supports animating React components using a typing and deleting effect. This feature is currently in **beta**, and feedback is welcome.\n\n### ✨ Default Behavior – Typing Animation\n\nBy default, TypingFX assumes the component is **pure** and attempts to extract and animate its **JSX output**, treating it like static content. This provides a natural typing effect as if the component was written inline.\n\n```tsx\n\u003cTypingFX\u003e{\u003cMyPureComponent /\u003e}\u003c/TypingFX\u003e\n```\n\nThis enables smooth, character-by-character typing that matches the surrounding text.\n\n### 🧩 `componentAnimation` Prop\n\nFor components with side effects or dynamic behavior, you can control their animation using the `componentAnimation` prop:\n\n```tsx\n\u003cTypingFX\n  componentAnimation={{\n    wrapper: \"div\",\n    props: { className: \"custom-wrapper\" },\n  }}\u003e\n  \u003cMyComponent /\u003e\n\u003c/TypingFX\u003e\n```\n\nTypingFX will wrap the component with the specified element and apply:\n\n- **Fade-in (typing)**: 5s\n- **Fade-out (deleting)**: 3s\n\nThis disables JSX extraction and uses a wrapper-based animation strategy.\n\n### ⚠️ Server-Side Rendering (SSR) Limitation\n\nTypingFX cannot detect components in **SSR environments**. Thus, by default, SSR-rendered components are treated as normal content and animated using the default typing animation.\n\nHowever, you can manually mark any DOM element to be treated as a component by adding a `data-tfx` attribute with any truthy value:\n\n```html\n\u003cspan data-tfx=\"true\"\u003eServer-rendered content\u003c/span\u003e\n```\n\nCombined with the `componentAnimation` prop, this enables custom animation support even for SSR-rendered output.\n\n### 🎨 CSS Overrides\n\nYou can override the fade animation by targeting the default class names:\n\n```css\n.tfx_component.tfx_type {\n  animation: myCustomFadeIn 2s ease-in;\n}\n\n.tfx_component.tfx_del {\n  animation: myCustomFadeOut 2s ease-out;\n}\n```\n\n---\n\n### 💬 API Feedback Welcome\n\nWe're exploring the best API design for component animation. If you have ideas or requirements, please open an [issue](https://github.com/react18-tools/typingfx/issues) or comment on [this discussion](https://github.com/react18-tools/typingfx/discussions/4).\n\n---\n\n## 💡 Tips \u0026 Tricks\n\n### ⏱️ Delays \u0026 Pauses with Numbers\n\nYou can embed numbers (e.g. `{1000}`) directly inside JSX (`steps` **or** `children`) to add typing or deleting delays:\n\n```tsx\n\u003cTypeOut\n  steps={[\n    \u003c\u003e\n      Hello{800}\n      {-500}\n    \u003c/\u003e,\n    \"World!\",\n  ]}\n/\u003e\n```\n\n- `{800}` → pauses for 800ms while typing\n- `{-500}` → pauses for 500ms while deleting\n\n\u003e ⚠️ **Important**: Numbers must be embedded directly as JSX expressions — not as strings.\n\nIf you want to display a number instead of pausing, convert it to a string:\n\n```tsx\n\u003c\u003eI waited {String(800)} milliseconds.\u003c/\u003e\n```\n\n---\n\n### ⚠️ Memoization Matters\n\nTo prevent unintended animation restarts on re-renders, **memoize** your `steps` or `children` using `useMemo`:\n\n```tsx\nconst steps = useMemo(() =\u003e [\"One\", \"Two\", \"Three\"], []);\n\u003cTypeOut steps={steps} /\u003e;\n```\n\nThis is especially useful in dynamic React apps or when props change frequently.\n\n---\n\n### 🧱 Multi-Line Typing Support\n\nEach step can contain **multiple elements** like `\u003cp\u003e`, `\u003cdiv\u003e`, or fragments – `typingfx` will animate them line by line:\n\n```tsx\n\u003cTypeOut\n  steps={[\n    \u003c\u003e\n      \u003cp\u003eHi there\u003c/p\u003e\n      \u003cp\u003eWelcome to TypingFX!\u003c/p\u003e\n    \u003c/\u003e,\n    \u003c\u003e\n      \u003cp\u003eHi there\u003c/p\u003e\n      \u003cp\u003eTypingFX is awesome!\u003c/p\u003e\n    \u003c/\u003e,\n  ]}\n/\u003e\n```\n\n\u003e ✅ No need to split them into separate steps – group them as one step to animate fluidly across lines.\n\n---\n\n### 🚫 Avoid Layout Shifts on Delays\n\nWhen inserting delays between block elements, prefer placing the delay **inside one block**, rather than between them:\n\n```tsx\n// ❌ Avoid: causes extra spacing\n\u003c\u003e\n  \u003cp\u003eHi\u003c/p\u003e\n  {5000}\n  \u003cp\u003eHello\u003c/p\u003e\n\u003c/\u003e\n\n// ✅ Recommended\n\u003c\u003e\n  \u003cp\u003eHi{5000}\u003c/p\u003e\n  \u003cp\u003eHello\u003c/p\u003e\n\u003c/\u003e\n// or\n\u003c\u003e\n  \u003cp\u003eHi\u003c/p\u003e\n  \u003cp\u003e{5000}Hello\u003c/p\u003e\n\u003c/\u003e\n```\n\n---\n\n### ✨ Control the Cursor\n\nWant to hide the blinking cursor?\n\n```tsx\n\u003cTypeOut noCursor\u003eHello, no cursor here!\u003c/TypeOut\u003e\n```\n\n---\n\n### 🌐 Seamless RSC \u0026 Next.js Support\n\nNo extra setup needed – `TypeOut` is already marked as a client component.\n\n\u003e ✅ Works out of the box with Next.js 14/15 and React Server Components (RSC).\n\n---\n\n## ⚙️ Props\n\n| Prop       | Type           | Default    | Description                                                |\n| ---------- | -------------- | ---------- | ---------------------------------------------------------- |\n| `steps`    | `ReactNode[]`  | `[\"\"]`     | The sequence of text or elements to animate.               |\n| `speed`    | `number`       | `20`       | Typing speed (characters per second).                      |\n| `delSpeed` | `number`       | `40`       | Deletion speed (characters per second).                    |\n| `repeat`   | `number`       | `Infinity` | Number of times to loop over steps.                        |\n| `noCursor` | `boolean`      | `false`    | Disables the blinking cursor.                              |\n| `paused`   | `boolean`      | `false`    | Manually pause or resume animation.                        |\n| `force`    | `boolean`      | `false`    | Forces animation even when `prefers-reduced-motion` is on. |\n| `children` | `ReactNode`    | `\"\"`       | An optional initial step to animate.                       |\n| ...        | `HTMLDivProps` | —          | Additional props are passed to the container element.      |\n\n---\n\n## 📦 Framework Compatibility\n\n- ✅ React 16.8 — React 19\n- ✅ Next.js 12 — Next.js 15\n- ✅ SSR-safe (no `window` access during render)\n- ✅ RSC-compatible (used as a client component)\n\n---\n\n## ❓ FAQ \u0026 Gotchas\n\n\u003cdetails\u003e\n\u003csummary\u003e⚠️ \u003cstrong\u003eWhy does the animation restart on every re-render?\u003c/strong\u003e\u003c/summary\u003e\n\nThis usually happens when `steps` or `children` are _not memoized_, causing a new reference on every render.\n\n✅ **Fix:** Use `useMemo` to ensure stable references:\n\n```tsx\nconst steps = useMemo(() =\u003e [\"Hello\", \"World\"], []);\n\u003cTypeOut steps={steps} /\u003e;\n```\n\n\u003c/details\u003e\n\n---\n\n\u003cdetails\u003e\n\u003csummary\u003e📏 \u003cstrong\u003eWhy is there extra space when adding delays between elements?\u003c/strong\u003e\u003c/summary\u003e\n\nInserting a delay like `{500}` **between block elements** (e.g. `\u003cp\u003e`) creates empty text nodes, leading to layout shifts.\n\n❌ Bad:\n\n```tsx\n\u003c\u003e\n  \u003cp\u003eHi\u003c/p\u003e\n  {500}\n  \u003cp\u003eHello\u003c/p\u003e\n\u003c/\u003e\n```\n\n✅ Good:\n\n```tsx\n\u003c\u003e\n  \u003cp\u003eHi{500}\u003c/p\u003e\n  \u003cp\u003eHello\u003c/p\u003e\n\u003c/\u003e\n```\n\n\u003e 📌 **Tip:** Always place delays _inside_ a block to avoid glitches.\n\n\u003c/details\u003e\n\n---\n\n\u003cdetails\u003e\n\u003csummary\u003e🧩 \u003cstrong\u003eDoes it work with RSC \u0026 Next.js 14/15?\u003c/strong\u003e\u003c/summary\u003e\n\nAbsolutely. `TypeOut` is already marked as a **client component**, so it works out of the box with:\n\n- ✅ React Server Components (RSC)\n- ✅ App Router\n- ✅ Server-side Rendering (SSR)\n\u003c/details\u003e\n\n---\n\n\u003cdetails\u003e\n\u003csummary\u003e⏪ \u003cstrong\u003eHow do I add delay during deleting?\u003c/strong\u003e\u003c/summary\u003e\n\nUse **negative numbers** like `{-500}` anywhere in the content.\n\n- `{800}` → pause for 800ms while typing\n- `{-500}` → pause for 500ms while deleting\n\n```tsx\n\u003cTypeOut steps={[\"Start typing...\", -1000, \"Deleting now...\"]} /\u003e\n```\n\nor\n\n```tsx\n\u003cTypeOut\u003eWait before deleting me{-500}\u003c/TypeOut\u003e\n```\n\n\u003c/details\u003e\n\n---\n\n\u003cdetails\u003e\n\u003csummary\u003e🎨 \u003cstrong\u003eHow do I animate styled or rich text?\u003c/strong\u003e\u003c/summary\u003e\n\nTypingFX supports JSX out of the box! You can mix `\u003cstrong\u003e`, `\u003ccode\u003e`, emojis, or even full components.\n\n```tsx\n\u003cTypeOut\n  steps={[\n    \u003c\u003e\n      Writing with \u003cstrong\u003estyle\u003c/strong\u003e\n    \u003c/\u003e,\n    \u003c\u003e\n      Deployed via \u003ccode\u003eVercel\u003c/code\u003e\n    \u003c/\u003e,\n    \u003c\u003e💻 Happy Coding!\u003c/\u003e,\n  ]}\n/\u003e\n```\n\n\u003e ✨ Fully supports React elements, fragments, and inline styles.\n\n\u003c/details\u003e\n\n---\n\n## 📁 License\n\nMPL-2.0 open-source license © [Mayank Chaudhari](https://github.com/mayank1513)\n\n\u003e \u003cimg src=\"https://raw.githubusercontent.com/mayank1513/mayank1513/main/popper.png\" style=\"height: 20px\"/\u003e Please enroll in [our courses](https://mayank-chaudhari.vercel.app/courses) or [sponsor](https://github.com/sponsors/mayank1513) our work.\n\n\u003chr /\u003e\n\n\u003cp align=\"center\" style=\"text-align:center\"\u003ewith 💖 by \u003ca href=\"https://mayank-chaudhari.vercel.app\" target=\"_blank\"\u003eMayank Kumar Chaudhari\u003c/a\u003e\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freact18-tools%2Ftypingfx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freact18-tools%2Ftypingfx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freact18-tools%2Ftypingfx/lists"}