Step 25: Rich Text Editor

We are going to use Mantine UI's Rich Text Editor. Let's add it as a dependency to our application:

yarn add @mantine/rte

Now we are going to update the Edit.jsx:

  • Add RichTextEditor from @mantine/rte instead of Textarea from @mantine/core.

  • Take our the <Textarea /> component and instead add the following:

    <RichTextEditor
      id="rte"
      defaultValue={"Your note's text"}
      value={text}
      onChange={setText}
    />
    
  • Finally, delete handleTextChange function as you don't need it anymore!

Here is the updated Edit.jsx
import { Button, Container, Group, Stack } from "@mantine/core";
import { TextInput } from "@mantine/core";
import { useEffect, useState } from "react";
import PropTypes from "prop-types";
import { useNavigate, useLocation } from "react-router-dom";
import { RichTextEditor } from "@mantine/rte";

function Edit(props) {
  const { edit, remove } = props;
  const navigate = useNavigate();
  const location = useLocation();

  const [id, setId] = useState("");
  const [title, setTitle] = useState("");
  const [text, setText] = useState("");
  const [mode, setMode] = useState("");

  useEffect(() => {
    if (location.state === null) {
      navigate("/", { replace: true });
    } else {
      location.state.id !== id && setId(location.state.id);
      location.state.title !== title && setTitle(location.state.title);
      location.state.text !== text && setText(location.state.text);
      location.state.mode !== mode && setMode(location.state.mode);
    }
  }, [location.state]);

  const handleTitleChange = (event) => {
    setTitle(event.target.value);
  };

  const handleSave = () => {
    edit(id, title, text);
    navigate("/", { replace: true });
  };

  const handleCancel = () => {
    if (mode === "remove-on-cancel") {
      remove(id);
    }
    navigate("/", { replace: true });
  };

  return (
    <Container>
      <Stack spacing="lg">
        <TextInput
          placeholder="Your note's title"
          label="Title"
          withAsterisk
          value={title}
          onChange={handleTitleChange}
        />
        <RichTextEditor
          id="rte"
          defaultValue={"Your note's text"}
          value={text}
          onChange={setText}
        />
        <Group position="center" spacing="xl" grow>
          <Button variant="subtle" onClick={handleCancel}>
            Cancel
          </Button>
          <Button variant="default" onClick={handleSave}>
            Save
          </Button>
        </Group>
      </Stack>
    </Container>
  );
}

export default Edit;

Edit.propTypes = {
  edit: PropTypes.func.isRequired,
  remove: PropTypes.func.isRequired,
};

Next, we are going to update the components/Note.jsx file as follows:

- <Accordion.Panel>{note.text}</Accordion.Panel>
+ <Accordion.Panel>
+   <div dangerouslySetInnerHTML={{ __html: note.text }}></div>
+ </Accordion.Panel>  

The dangerouslySetInnerHTML allows you to insert note.text as an HTML inside <Accordion.Panel> instead of a string. We need this since the rich text editor saves the note text as an HTML.

Run the app and observe how it works now.