ReactJS: type writer effect like chatGPT
Creating a Typewriter Effect in React with React Markdown
In this blog post, I'll walk through how to create a typewriter effect for your React applications, perfect for adding a dynamic, interactive touch to your websites or applications. This effect will simulate the appearance of text being typed onto the screen in real-time. I will also integrate React Markdown to render Markdown-formatted text, adding an extra layer of functionality that allows you to include formatted text, links, tables, and more within your typewriter effect.
Getting Started
First, ensure you have a React project set up. If you need to set one up, you can do so by using Create React App:
npx create-react-app my-typewriter-effect cd my-typewriter-effect
Next, install react-markdown
and remark-gfm
to render Markdown-formatted text:
npm install react-markdown remark-gfm
Implementing the Typewriter Effect
The core of our typewriter effect is a React component named TypewriterEffect
. This component takes in a text string and optionally, a typing speed and a callback function to execute once the typing animation is complete. It uses the useState
and useEffect
hooks to manage the state and side effects, respectively.
Here's the code for the TypewriterEffect
component:
import { useEffect, useRef, useState } from 'react'; import CustomReactMarkdown from './components/CustomReactMarkdown'; import { processMarkdown } from './utils/questions'; // Assume this is a function you've defined to preprocess Markdown text. const TypewriterEffect = ({ text, typingSpeed = 10, onRenderingEnd, }) => { const [visibleLength, setVisibleLength] = useState(0); const processedText = processMarkdown(text); const contentRef = useRef(null); useEffect(() => { if (visibleLength < processedText.length) { const timer = setTimeout(() => { setVisibleLength(visibleLength + 1); }, typingSpeed); return () => clearTimeout(timer); } else if (onRenderingEnd) { onRenderingEnd(); } }, [visibleLength, processedText.length, typingSpeed, onRenderingEnd]); return ( <div ref={contentRef}> <CustomReactMarkdown content={processedText.substring(0, visibleLength)} /> {visibleLength < processedText.length && <span className="typing-indicator" />} </div> ); };
CustomReactMarkdown Component
The CustomReactMarkdown
component is a simple wrapper around the ReactMarkdown
component that configures it to use the remark-gfm
plugin, enabling GitHub Flavored Markdown, and sets up custom rendering for table elements to enhance their appearance.
import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; const CustomReactMarkdown = ({ content, className }) => ( <ReactMarkdown className={className} remarkPlugins={[remarkGfm]} components={{ // Custom renderers for table elements th: ({ node, ...props }) => <th className="th" {...props} />, td: ({ node, ...props }) => <td className="td" {...props} />, // Add other custom renderers as needed }} > {content} </ReactMarkdown> );
Styling
To make our typewriter and Markdown content look nice, I include some basic CSS:
.typewriter-effect { font-family: 'Courier New', Courier, monospace; white-space: pre-wrap; } .typing-indicator { display: inline-block; width: 10px; height: 20px; background-color: currentColor; animation: blink 1s step-start infinite; } @keyframes blink { 50% { opacity: 0; } } /* Add styles for the table components from CustomReactMarkdown here */ .table-bordered { border: 1px solid #e9ecef; border-radius: 0.25rem; width: 100%; } .th, .td { background-color: #f8f9fa; border: 1px solid #e9ecef; padding: 0.75rem; text-align: left; }
Conclusion
By combining React's state management and effect hooks with react-markdown
, I've created a versatile typewriter effect component that can handle Markdown-formatted text. This effect can add a touch of dynamism and interactivity to your applications, making your content stand out.
Experiment with the TypewriterEffect
component by adjusting the typingSpeed
prop or by using different Markdown
content to see how it behaves. This component is a great starting point for more complex animations and could be extended with additional features like pausing/resuming the animation or integrating other types of content.