Notion like Placeholders for every line — Slatejs
Tags: slatejs, javascript, programming, webdev
Published: 2021-09-18 10:00:29

---
title: Notion like Placeholders for every line — Slatejs
published: true
date: 2021-09-17 18:59:47 UTC
tags: slatejs,javascript,programming,webdev
---

### Notion like Placeholders for every line — Slatejs

![Notepad](https://cdn-images-1.medium.com/max/1024/1*tHhrhRPimSXMwdZceaVQPA.jpeg)<figcaption>Photo by <a href="https://unsplash.com/@diana_pole?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Diana Polekhina</a> on <a href="https://unsplash.com/s/photos/notepad?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption>

I have recently worked on building a module that includes a google docs kind of functionality. I was exploring several JavaScript frameworks around building editors, and I finally choosed Slatejs

One feature of my editor was to have a placeholder for every line similar to Notion. By default, Slatejs provides a placeholder but it will be rendered if the document only contains a single empty block.

However, Slate.js doesn’t have the feature that I needed. I was able to figure out a solution with the help of the amazing Slate.js community members and thought to share this with you.

The solution I implemented was to check if a node is empty and then display a dummy text using CSS tricks.

```
.selected-empty-element {
  position: relative;
}

.selected-empty-element:after {
  content: " Use '/' to create question";
  color: #aaa;
  position: absolute;
  top: 0;
}
```

In the render element method, I will add this class selected-empty-element if the node is empty.

```
const Element = (props): JSX.Element => {
  const { children } = props;
  const isEmpty =
    children.props.node.children[0].text === “” &&
    children.props.node.children.length === 1;

  return (
    <p {…props} className={isEmpty ? “selected-empty-element” : “”}>
      {children}
    </p>
  );
};
```

But this gives out a weird user experience when you have multiple empty rows. All empty lines will show the placeholders.

![Multiple empty rows in editor](https://cdn-images-1.medium.com/max/650/1*uCvAksHe2bL7RXClGxq4LA.gif)

So one solution I could think of was to check if that particular line has focus. I added a check using useSelected, and it looked exactly like the solution I needed.

```
const selected = useSelected();
return (
  <p {...props} 
    className={selected && isEmpty ? "selected-empty-element" : ""}
  >
    {children}
  </p>
);
```

![placeholder only on selection](https://cdn-images-1.medium.com/max/653/1*4XC3VH53nJ8oiJ0MaPUiJA.gif)

However, there was one problem that I found later on. If I select the whole document, then the useSelected is true for all nodes and I could see the placeholder for all nodes.

![the whole document is selected](https://cdn-images-1.medium.com/max/650/1*NrfKd0ONnbV5mGXOtAr_ZQ.gif)

Now I had to add another check to see if my selection is empty or not. I used the available library methods to see if the Range is collapsed or not using

```
const editor = useSlate();
const selection = editor.selection;
let isSelectionCollapsed = true;
if (selection !== null)
 isSelectionCollapsed = Range.isCollapsed(editor.selection);
```

So now the final Element code is

```
const Element = (props): JSX.Element => {
  const { children } = props;
  const selected = useSelected();
  const editor = useSlate();
  const selection = editor.selection;
  let isSelectionCollapsed = true;
  if (selection !== null)
    isSelectionCollapsed = Range.isCollapsed(editor.selection);
  
  const isEmpty =
    children.props.node.children[0].text === “” &&
    children.props.node.children.length === 1;

  return (
    <p {…props}
      className={ selected && isSelectionCollapsed && isEmpty
        ? “selected-empty-element” : “”
      }
    >
      {children}
    </p>
  );
};
```

This was the final solution that I needed. You can find the complete editor code in this sandbox here -

{% codesandbox r69jf %}

I hope this was helpful. Share with me some of the interesting features you built using Slatejs.