React boosting Textareas and Inputs.
Tags: react, javascript, frontend
Published: 2020-06-16 11:01:51

---
title: React boosting Textareas and Inputs.
published: true
description: What to do when Textareas and Inputs just don't cut the mustard for your use case.
tags: react, javascript, frontend
cover_image: https://i.ibb.co/j9Yh5BZ/Screenshot-2020-06-16-at-11-24-46.png
---


I was recently forced into the world of custom text editors again, after a fairly long hiatus. Text (especially rich text) has always been one of those areas that tools fall on either end of the 'too simple' to 'too complex' spectrum. Where simple tools don't offer what you need and complex ones offer too much. There is also the phenomena of 'it works but' where a requirement isn't ticked and you question whether you can convince stakeholders to drop it. My recent project was a simple input, that had a non-trivial view, but it had to work flawlessly. It looks like this:

![preview](https://i.ibb.co/R6D6RqH/Screenshot-2020-06-16-at-11-30-52.png)

It allows the user to type free text and displays an emoji above each character as a secret 'code'. What I knew early on is it had to work like a real text input, it needed to support copy/paste and select, and line breaks and all that good stuff. The early ideas looked at content editable tags, and capturing keyboard events and doing all sorts of mad complicated stuff. In the end what I looked into was 'boosting' an input, a `textarea` in this case. By 'boosting' I mean taking the natural implementation and hooking things off of it to give it additional functionality. In this case, there is a `textarea` that isn't visible and the component controls `focus` as well as `onChange` and other events. Starting off with the usual:

```js
  const textareaRef = createRef();
  const [value, setValue] = useState('');
```

It then boils down to two functions that take care of keeping track of the value, and keeping track of the selection and focus. 

```js
  const onTextareaChange = (evt) => {
    onChange(evt.target.value);
    setSelection();
  };
  const setSelection = () => {
    setStart(textareaRef.current.selectionStart);
    setEnd(textareaRef.current.selectionEnd);
    setSelected(textareaRef.current === document.activeElement);
  };
```

These are meant to be as general purpose as possible. The `onTextareaChange` is what you have all probably written dozens of times, but the `setSelection` is reasonably elegant. It sets three state values `start`, `end` and `selected`. Where `start` and `end` are the range of characters currently selected (also used to work out the position of my fake caret), and `selected` being a boolean showing focus. From here the rest of the component can do whatever it wants to show the 'output'. In my case I actually used click events on each 'letter' that it shows to change the selection:

```js
  const onSelect = (idx = 0) => {
    if (onChange && !disabled) {
      textareaRef.current.focus();
      textareaRef.current.selectionStart = idx;
      textareaRef.current.selectionEnd = idx;
      setSelection();
    }
  };
```

This will be updated to support drag selections eventually, but it simply expects an index as in the `value` index clicked. This will then ensure the `textarea` has focus and sets the selection back to trigger any other logic. 

Generally this is pretty clean, and even with some additional animation is quite snappy in my particular use case. 

![demo](https://media.giphy.com/media/l0XWmUCsuKZ6cml3YC/giphy.gif)

I also used the same technique for an input view, where the user has to decode the secret message. Which used individual `input` tags and some focus change magic:

![demo_2](https://media.giphy.com/media/LrWcKRoQoGSi1Uoine/giphy.gif)

I'll clean up the code and share if people are interested, and you can go check out the finished app and write your own messages at [mojimess](https://mojimess.com), an app built for 6 year olds 😎