Paramanantham Harrison Web and mobile app developer. Love exploring the depth of JS fullstack development. React, Vue, React Native, Next JS, and GraphQL are my current love interests. Find me online at learnwithparam.com.

Building inline editable UI in React: A complete guide

7 min read 1961

Building Inline Editable UI in React

Editor’s note: This React inline editable UI tutorial was last updated on 30 March 2021.

User interfaces in React applications are becoming more complex by the day. As client-side UI libraries become increasingly powerful, we can create even more exciting user experiences by experimenting with React inline editable UI components such as editable tables, lists, and text fields.

Below is an example of a basic React inline editable UI:

A gif showing editable UI in React.
Basic inline editable UI

In this tutorial, we’ll show you how to create basic inline editable UI components in React using a simplified version of Asana create task. Our editable UI will have only a task name and description field.

Here’s what we’ll cover:

Here’s a demo of the React editable UI we’ll build in this walkthrough.

Below are some of the most prominent products currently using inline editable UI with clear UX.

  • Asana: One of the best custom UIs with inline editable tables and forms
  • Trello: Trello cards can be edited by clicking on them
  • Airtable and Notion are some other modern apps that use inline editable UI elements
  • Google sheets: Inline editable smart table UI for the web
Google sheets UI

Before going deep into our custom implementation of inline editable components, let’s talk about some of the existing React components you can use to achieve various inline editable UI elements.

React inline editable UI component libraries

Below are some inline editable UI component libraries for React.

React editable text field components

React Inline Edit Kit, successor to ReactInlineEdit, is a collection of common HTML form elements that are editable inline.

We made a custom demo for .
No really. Click here to check it out.

react-inline-editing is a similar inline, editable text/label component for React.

These two packages are very simple and allow you to edit a label as an input box. You can customize the style based on your needs.

You can use React Inline Edit Kit and react-inline-editing with any table-like structure to create a React editable table.

react-contenteditable

react-contenteditable is arguably the most famous package for inline editable UI. The main difference between this component and others is that it allows you to inline edit HTML — not just text content.

This library can be used for markup and markdown editing in the UI. You can also manage the height of the editable element to create the look and feel of an input or a textarea element. Check out an example on CodeSandbox.

React editable table library

React Table is one of the most popular table libraries that allows you to edit inline. You can create a UI similar to Google Sheets by customizing React Table library components.

In March 2020, React Table creator Tanner Linsley released React Table v7, which he described as “the culmination of over a years [sic] worth of work to refactor the entire library to a hooks-only UI/Style/Markup agnostic table building utility.”

See our comprehensive guide to building and stying tables with react-table v7 for a closer look at what’s new in the most recent stable react-table release, or read on to learn how to render your own React table component with react-table.

You can also check out the React Table kitchen sink to see how this editable UI works in the table layout.

How editable UI works

Let’s explore how an editable UI works:

  • An editable UI will simply display a label
  • On hover, it will show the borders to make the UI look inline editable
  • On click, it will transform the simple label to a custom input element. Some of the notable input elements are input fields, textarea, select component, date picker, etc.
  • By clicking Enter or Escape, we’ll go back to the initial state and show the label
  • If you click Tab, it will once again switch to an input element and make the component accessible using the keyboard

For this tutorial, we’re going to build a simple version without the Tab functionality.

You can easily add the Tab functionality, but I left that as an exercise for you. You can create a pull request to my repo here.

Building a simple React component for editable UI

First, we’ll create a simple React app using create-react-app.

I’m using tailwindcss for styling. Read “How to use Tailwind CSS in React to configure Create React App” for more details.

Now let’s create the Editable React component:

// Editable.js
import React, { useState } from "react";

// Component accept text, placeholder values and also pass what type of Input - input, textarea so that we can use it for styling accordingly
const Editable = ({
  text,
  type,
  placeholder,
  children,
  ...props
}) => {
  // Manage the state whether to show the label or the input box. By default, label will be shown.
// Exercise: It can be made dynamic by accepting initial state as props outside the component 
  const [isEditing, setEditing] = useState(false);

// Event handler while pressing any key while editing
  const handleKeyDown = (event, type) => {
    // Handle when key is pressed
  };

/*
- It will display a label is `isEditing` is false
- It will display the children (input or textarea) if `isEditing` is true
- when input `onBlur`, we will set the default non edit mode
Note: For simplicity purpose, I removed all the classnames, you can check the repo for CSS styles
*/
  return (
    <section {...props}>
      {isEditing ? (
        <div
          onBlur={() => setEditing(false)}
          onKeyDown={e => handleKeyDown(e, type)}
        >
          {children}
        </div>
      ) : (
        <div
          onClick={() => setEditing(true)}
        >
          <span>
            {text || placeholder || "Editable content"}
          </span>
        </div>
      )}
    </section>
  );
};

export default Editable;

The component is very straightforward:

  • If the isEditing state is true, then it displays the children. That’s where we pass the input or textarea elements. The input state will be managed outside of this component
  • If the isEditing state is false, then we display the simple label text or placeholder depending on whether the text value is empty or not

Let’s see what a simple input editable component looks like:

// App.js - Input editable UI

import React, { useState } from "react";
import Editable from "./Editable";

function App() {
  // State for the input
  const [task, setTask] = useState("");

  /*
    Enclose the input element as the children to the Editable component to make it as inline editable.
  */
  return (
    <Editable
      text={task}
      placeholder="Write a task name"
      type="input"
    >
      <input
        type="text"
        name="task"
        placeholder="Write a task name"
        value={task}
        onChange={e => setTask(e.target.value)}
      />
    </Editable>
  );
}

export default App;

Here we enclosed input inside the Editable component. You can enclose any custom form component to make it an editable UI.

This is a pretty simple example. If you want to create a more complex example for editable UI you can create Higher order components or custom Hooks to manage all the states outside the editable component.

Let’s see how the editable component works for a textarea:

<Editable
  text={description}
  placeholder="Description for the task"
  type="textarea"
>
  <textarea
    name="description"
    placeholder="Description for the task"
    rows="5"
    value={description}
    onChange={e => setDescription(e.target.value)}
  />
</Editable&gt

It’s that simple. We just swapped the input element with a textarea, and it works as long as we provide the proper CSS based on the type we pass the  Editable component.

However, we’ll run into a few problems:

  • When we click on the label, it won’t auto-focus on the input element
  • A simple form can be navigated using the Tab key. However, an inline editable UI can’t be navigated without manually implementing that functionality

Solving the focus issue

To solve the focus issue, we need to use a reference to the input element and focus it when the edit state is set:

// App.js
import React, { useRef, useState } from "react";
import Editable from "./Editable";

function App() {
  /* 
    1. create a reference using use reference and add the ref={inputRef} to input element
    2. pass this reference to the Editable component, use different name than ref, I used `childRef`. Its basically a normal prop carrying the input element reference.
  */
  const inputRef = useRef();
  const [task, setTask] = useState("");

  return (
    <Editable
      text={task}
      placeholder="Write a task name"
      childRef={inputRef}
      type="input"
    >
      <input
        ref={inputRef}
        type="text"
        name="task"
        placeholder="Write a task name"
        value={task}
        onChange={e => setTask(e.target.value)}
      />
    </Editable>
  );
}
export default App;

Next, we’ll pass the input element reference to the Editable component, then focus when the isEditing state is true:

// Editable.js
import React, { useState, useEffect } from "react";
import "./Editable.css";

const Editable = ({ childRef, ... }) => {
  const [isEditing, setEditing] = useState(false);

  /* 
    using use effect, when isEditing state is changing, check whether it is set to true, if true, then focus on the reference element
  */ 
  useEffect(() => {
    if (childRef && childRef.current && isEditing === true) {
      childRef.current.focus();
    }
  }, [isEditing, childRef]);

  const handleKeyDown = (event, type) => {
    ...
  };

  return (
    ...
};

export default Editable;

Glitches with keydown events

There are a few things to be aware of when dealing with keydown events.

For the input element, all the keys (Enter, Escape and Tab key) will set the isEditing state to false.

For textarea, the enter key has to add a new line inside textarea, so we need to handle this use case separately:

const handleKeyDown = (event, type) => {
    const { key } = event;
    const keys = ["Escape", "Tab"];
    const enterKey = "Enter";
    const allKeys = [...keys, enterKey]; // All keys array

  /* 
    - For textarea, check only Escape and Tab key and set the state to false
    - For everything else, all three keys will set the state to false
  */
    if (
      (type === "textarea" && keys.indexOf(key) > -1) ||
      (type !== "textarea" && allKeys.indexOf(key) > -1)
    ) {
      setEditing(false);
    }
}:

Exercise: Accessibility for forms with Tab key navigation

By default, input and textarea are hidden. As a result, we can’t navigate the form fields just by hitting the Tab key.

To achieve keyboard support, we need to monitor the Tab key event on the component or on the whole page and set the state manually to each element. Then we can navigate to the next form element on the next keypress.

We didn’t implement this in our example code, but it’s worth a try to make sure you can handle keypress events on a page in React.

When to use React inline editable UI

You don’t need to use inline editable UI for most basic form needs.

However, for complex React applications where you have lots of content with edit options, it’s best to build both view and edit in a single place. If you don’t, you’ll have to maintain two different UIs.

Limitations of inline editable UI in React

The most significant challenges you may run into in inline editable UI involve showing errors. You should account for this when thinking about the UX.

You may also have difficulty achieving the level of accessibility necessary to support mouse events. Touch events will likely also be an issue.

Finally, supporting mobile devices can be hard when you have form elements hidden. This will be especially tricky if the UI has to support a mobile layout, because there is no hover to show users whether the field is editable inline on touch screens.

Conclusion

This has been a simple example and overview on how to create inline editable components in React.

Try to use existing components, but if none of the existing ones fit your needs you can create custom ones.

You can check out the demo here and the codebase here.

Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — .

Paramanantham Harrison Web and mobile app developer. Love exploring the depth of JS fullstack development. React, Vue, React Native, Next JS, and GraphQL are my current love interests. Find me online at learnwithparam.com.

Testing accessibility with Storybook

One big challenge when building a component library is prioritizing accessibility. Accessibility is usually seen as one of those “nice-to-have” features, and unfortunately, we’re...
Laura Carballo
4 min read

4 Replies to “Building inline editable UI in React: A complete guide”

  1. Hey, nice tut – I was trying by adding the tab functionality but did succeeded yet, if you can give some tips how to implement it would be appreciated.

    Cheers,
    Andrea

  2. Is there a comparison of react-easy-edit (Mark A) with the other tools listed, and also do these other solutions cost money?

Leave a Reply