ReactJS: type writer effect like chatGPT

DALL·E 2024-04-04 11.48.28 - Create a captivating hero image for a blog post about creating a typewriter effect in React applications. The image should depict a vintage typewriter.webp

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.