Slate | Editor in 10min with Next.js and TS ✍️
Published: 2022-10-17 08:05:37

## What we're going to do? 
Building a holistic rich text editor experience for a good user experience is hard, but recently I found **Slate**

![Slate repo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/849qp6rvdp7b5qhyy85f.png)
[Link to Repo](https://github.com/ianstormtaylor/slate)

Slate is a customizable framework for building rich text editors. The community around Slate looked pretty active, so we Zirkular it a shot. After some quick prototypes I was stunned how easy it is to use Slate out of the box **in minutes**.

So we use Slate now for 3 month. Now I felt like it's time to give something back to open source. So this should become a **blog series** with little slate tutorials in addition to the [Slate Docs](https://docs.slatejs.org).

I tried to make a very detailed description, so if you follow the steps you should get to the goal in 10 minutes. If you have problems or questions feel free to use the comment section.

You can find the final state of the code in this repo.
[zirkular-os-projects](https://github.com/zirkular-os/slate-tutorial-1)

### Step 1 - Create Next.js App 🏗
Use the following command in the terminal to create a Next.js app. [Reference](https://nextjs.org/docs/api-reference/create-next-app)
`yarn create next-app`
Go through the process of _crest-next-app_. After it's finished you have the app in your root. Now your app is ready for development.

### Step 2 - Clean up time 🧹
For having a nice clean project it's time to delete the stuff that we don't need. 

- Delete Home.module.css
- Delete content in public folder
- Update index.js in pages folder
    - Remove any the imports
    - Remove any jsx elements so its only one `div` in it
- Update _app.js in pages folder
    - make sure to import `"../styles/globals.css"`

Your folder structure should now look like this.
![folder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ylxnquig4ji4ip4vxtyg.png)

Your updated `index.js` file should look like this.
```react
export default function Home() {
  return <div>Editor Page</div>
}
```
Your updated `_app.js` file should look like this.
```react
import "../styles/globals.css";

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

export default MyApp;
```
Your updated `styles/gloabals.css` file should look like this.
```react
html,
body {
  padding: 0;
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
    Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}
```
On your index page you now have the simple headline _Editor Page_ on an empty page.

### Step 3 - Make it type-safe 🌟
To use Typescript in our setup we have to make some configurations in the `tsconfig.json` file. We don't have the file yet, so create it at the root level. The file should contain:
```react
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules", "cypress"]
}
```

### Step 4 - Create the editor component 🧩
To add components to a Next.js project you have to create a `component` folder (you can also name that different) on the root level of your app. After that you can add the file `myEditor.tsx` to this folder.

In this component we write a simple function component. With a simple text like `My Editor`.
```react
const MyEditor = () => {
  return <div>My Editor</div>
}

export default MyEditor;
```

Now you can call the component in your `index.js` file.
```react
import MyEditor from "./../components/myEditor"

export default function Home() {
  return (
    <div>Editor Page
      <MyEditor />
    </div>
  )
}
``` 

Because at some point in time we want to style this component we use the `module.css` scoped styling strategy. Therefore we add the `Editor.module.css` file in the `styles` folder.

We are not going to use some styling but for the next blog we need this to be in place. 

Import the styling in the component so we can now use 'styles' now in the component. 
```react
import styles from "../styles/Editor.module.css";

const MyEditor = () => {
  return <div>My Editor</div>
}

export default MyEditor;
```

So if we have done everything right we see now that we have the _Editor Page_ text from the `index.js` component and the _My Editor_ text from the `component/myEditor.tsx`.

### Step 5 - Adding Slate 🚀
Use the following commands to add Slate with you terminal. 
`yarn add slate slate-react`
`yarn add react react-dom`

The next steps are probably a duplication of the installing Slate tutorial at the [docs](https://docs.slatejs.org/walkthroughs/01-installing-slate) but I will still cover this section, because I felt kind of confused sometimes because it's switching between js and ts.

Once you've installed Slate, you'll need to import it and also some types for type-safety.
```react
import { useState } from "react";

// Import the Slate editor factory.
import { createEditor } from 'slate';

// Import the Slate components and React plugin.
import { Slate, Editable, withReact } from 'slate-react';

//For TypeScript
import { BaseEditor } from 'slate';
import { ReactEditor } from 'slate-react';


declare module 'slate' {
  interface CustomTypes {
    Editor: BaseEditor & ReactEditor
    Element: CustomElement
    Text: CustomText
  }
}

type CustomElement = { type: 'paragraph'; children: CustomText[] }
type CustomText = { text: string }
```

The next step is to create a new Editor object in our component.
```react
const MyEditor = () => {
  const [editor] = useState(() => withReact(createEditor()))
  return <div>My Editor</div>
}
```

Now create the editor's `initialValue` outside of the function. Slate processes an object in the background that contains all the nodes and inline elements of our editor.
```react
const initialValue: CustomElement[] = [
  {
    type: 'paragraph',
    children: [{ text: 'A line of text in a paragraph.' }],
  },
]
```
We can use this `initialValue` to set this object, but remember that we can only use this `value` prop to set an initial state. It is not intended to change the value of the editor like in a controlled input field. So add the `Slate` component and pass in the `editor` and `value` prop. You can think of the `Slate` component as providing a context to every component underneath it.
```react
const MyEditor = () => {
  const [editor] = useState(() => withReact(createEditor()))
  return <Slate editor={editor} value={initialValue}>
    <Editable />
  </Slate>
}
```

In the end the `myEditor.tsx` file should look like this.
```typescript
import styles from "../styles/Editor.module.css";
import { useState } from "react";

// Import the Slate editor factory.
import { createEditor } from 'slate';

// Import the Slate components and React plugin.
import { Slate, Editable, withReact } from 'slate-react';

//For TypeScript
import { BaseEditor } from 'slate';
import { ReactEditor } from 'slate-react';

declare module 'slate' {
  interface CustomTypes {
    Editor: BaseEditor & ReactEditor
    Element: CustomElement
    Text: CustomText
  }
}

type CustomElement = { type: 'paragraph'; children: CustomText[] }
type CustomText = { text: string }


const initialValue: CustomElement[] = [
  {
    type: 'paragraph',
    children: [{ text: 'A line of text in a paragraph.' }],
  },
]

const MyEditor = () => {
  const [editor] = useState(() => withReact(createEditor()))
  return <Slate editor={editor} value={initialValue}>
    <Editable />
  </Slate>
}

export default MyEditor;
```

### Step 6 - Cheering 🎉
Look at the result. Now you can edit the text. It's only plain text, but a good foundation to start expanding the functionality. 

In the next part we are going to create the first element types. 

If you want to see how a finished version could look like, check out our community-first platform for open source projects: [Zirkular](https://zirkular.dev) 

![Zirkular](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/652fez5a28wqb4b47e33.jpg)