DEV Community

Cover image for Create your own custom cursor in a text area
Phuoc Nguyen
Phuoc Nguyen

Posted on • Originally published at phuoc.ng

Create your own custom cursor in a text area

Have you ever noticed that vertical blinking line that shows where the next character will go when you're typing? That's called a caret. And did you know you can customize it? It's true!

Customizing the caret can be super useful. For example, in a code editor, changing the shape and color of the caret could help with readability and make it easier to see different types of text. And in a chat app, a personalized cursor could add a fun touch to the user experience. You can even use custom cursors to create cool visual effects on a webpage.

By default, the caret is just a plain vertical line. But with CSS, you can change its shape and color using the caret-shape or caret-color property. Unfortunately, you can't make it wider or add animations that way.

But don't worry! In this post, we'll show you how to create a custom caret in a text area using JavaScript.

Hiding the default cursor

It's the pretty easy to make the default cursor disappear. All you need to do is set the caret-color property to a transparent color. This will make the default cursor look like it's vanished into thin air.

.container__textarea {
    caret-color: transparent;
}
Enter fullscreen mode Exit fullscreen mode

Creating a fake cursor

If you've been following our post on how to calculate cursor coordinates, you know that we've built the mirror element content using three parts: two text nodes representing the text before and after the cursor position, and an empty element representing the cursor.

But here's the cool part: we can use that empty element as a fake cursor! First, we'll add a special CSS class for it:

const pre = document.createTextNode(textBeforeCursor);
const post = document.createTextNode(textAfterCursor);
const caretEle = document.createElement('span');
caretEle.classList.add('container__cursor');
caretEle.innerHTML = ' ';

mirroredEle.innerHTML = '';
mirroredEle.append(pre, caretEle, post);
Enter fullscreen mode Exit fullscreen mode

Now that we've added the container__cursor class to the cursor element, we have full control over its appearance. We can add a background or increase the width, like this:

.container__cursor {
    background-color: rgb(15 23 42);
    width: 4px;
}
Enter fullscreen mode Exit fullscreen mode

And voila! With just a few lines of code, we've created a fake cursor in CSS.

Adding a blink effect to the fake cursor

To make your fake cursor look more realistic, you can make it blink. There are a few ways to achieve this effect, such as repeatedly changing the background color or opacity.

In this example, we'll use the first approach by defining a keyframe named blink using the @keyframes rule. This keyframe has three steps: 0%, 50%, and 100%. At 0% and 100%, we set the background color of the cursor to transparent, which makes it disappear. At 50%, we set the background color to a specific color, such as rgb(15 23 42), which makes it visible.

@keyframes blink {
    0%, 100% {
        background-color: transparent;
    }
    50% {
        background-color: rgb(15 23 42);
    }
}
Enter fullscreen mode Exit fullscreen mode

Next, we apply this animation to our cursor element using the animation property in CSS. We set its value to blink, specify a duration of 1 second, and make it repeat infinitely by setting its iteration count to infinite. Feel free to adjust these CSS styles to match your specific needs.

.container__cursor {
    animation: blink 1s infinite;
}
Enter fullscreen mode Exit fullscreen mode

With these styles applied, your custom cursor will now blink at a regular interval, giving it a more realistic appearance.

Moving the fake cursor alongside the real one

Now, let's talk about the final piece of the puzzle: moving the fake cursor in sync with the real one.

Usually, there's no built-in event to detect when users move the cursor inside a text area. However, we can use the selectionchange event, which is triggered when users select text on the page, focus on a text area, or move the cursor inside it.

To re-position the cursor, we handle the selectionchange event and check whether the text area is currently being focused by comparing the active element (document.activeElement) with the text area. If they match, we update the mirrored element, which includes the fake cursor element.

Here's a code snippet to give you an idea of how it works:

const handleSelectionChange = () => {
    if (document.activeElement === textarea) {
        // Re-update the mirrored element ...
    }
};

document.addEventListener('selectionchange', handleSelectionChange);
Enter fullscreen mode Exit fullscreen mode

Now let's take a look at our final example of the steps we've been following. You can either click or use the arrow keys to move the cursor, and the fake cursor will instantly move to the position you want it to be.

See also


It's highly recommended that you visit the original post to play with the interactive demos.

If you found this series helpful, please consider giving the repository a star on GitHub or sharing the post on your favorite social networks 😍. Your support would mean a lot to me!

If you want more helpful content like this, feel free to follow me:

Top comments (0)