Compare commits
4 Commits
v3.0.0-bet
...
2_0/docs/r
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a326ed817c | ||
|
|
172684345a | ||
|
|
5abb0ca8e6 | ||
|
|
9478cfecbc |
@@ -12,18 +12,12 @@ keywords: rich text, fields, config, configuration, documentation, Content Manag
|
||||
</Banner>
|
||||
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/richtext.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/richtext-dark.png"
|
||||
srcLight="https://cms.payloadcms.com/media/lexical-rich-text-field.png"
|
||||
srcDark="https://cms.payloadcms.com/media/lexical-rich-text-field-dark.png"
|
||||
alt="Shows a Rich Text field in the Payload admin panel"
|
||||
caption="Admin panel screenshot of a Rich Text field"
|
||||
caption="A screenshot of the Rich Text field in the Payload admin panel"
|
||||
/>
|
||||
|
||||
The Admin component is built on the powerful [`slatejs`](https://docs.slatejs.org/) editor and is meant to be as extensible and customizable as possible.
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Consistent with Payload's goal of making you learn as little of Payload as possible, customizing and using the Rich Text Editor does not involve learning how to develop for a <em>Payload</em> rich text editor.</strong> Instead, you can invest your time and effort into learning Slate, an open-source tool that will allow you to apply your learnings elsewhere as well.
|
||||
</Banner>
|
||||
|
||||
### Config
|
||||
|
||||
| Option | Description |
|
||||
@@ -38,88 +32,13 @@ The Admin component is built on the powerful [`slatejs`](https://docs.slatejs.or
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`editor`** | RichText editor which will be used by this field. |
|
||||
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
||||
| **`editor`** | RichText editor which will be used by this field, such as [`Lexical()`](/docs/rich-text/lexical)|
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
### Admin config
|
||||
|
||||
In addition to the default [field admin config](/docs/fields/overview#admin-config), the Rich Text editor allows for the following admin properties:
|
||||
|
||||
**`placeholder`**
|
||||
|
||||
Set this property to define a placeholder string in the text input.
|
||||
|
||||
**`elements`**
|
||||
|
||||
The `elements` property is used to specify which built-in or custom [SlateJS elements](https://docs.slatejs.org/concepts/02-nodes#element) should be made available to the field within the admin panel.
|
||||
|
||||
The default `elements` available in Payload are:
|
||||
|
||||
- `h1`
|
||||
- `h2`
|
||||
- `h3`
|
||||
- `h4`
|
||||
- `h5`
|
||||
- `h6`
|
||||
- `blockquote`
|
||||
- `link`
|
||||
- `ol`
|
||||
- `ul`
|
||||
- `textAlign`
|
||||
- `indent`
|
||||
- [`relationship`](#relationship-element)
|
||||
- [`upload`](#upload-element)
|
||||
- [`textAlign`](#text-align)
|
||||
|
||||
**`leaves`**
|
||||
|
||||
The `leaves` property specifies built-in or custom [SlateJS leaves](https://docs.slatejs.org/concepts/08-rendering#leaves) to be enabled within the Admin panel.
|
||||
|
||||
The default `leaves` available in Payload are:
|
||||
|
||||
- `bold`
|
||||
- `code`
|
||||
- `italic`
|
||||
- `strikethrough`
|
||||
- `underline`
|
||||
|
||||
**`hideGutter`**
|
||||
|
||||
Set this property to `true` to hide this field's gutter within the admin panel. The field gutter is rendered as a vertical line and padding, but often if this field is nested within a Group, Block, or Array, you may want to hide the gutter.
|
||||
|
||||
**`link.fields`**
|
||||
|
||||
This allows [fields](/docs/fields/overview) to be saved as extra fields on a link inside the Rich Text Editor. When this is present, the fields will render inside a modal that can be opened by clicking the "edit" button on the link element.
|
||||
|
||||
`link.fields` may either be an array of fields (in which case all fields defined in it will be appended below the default fields) or a function that accepts the default fields as only argument and returns an array defining the entirety of fields to be used (thus providing a mechanism of overriding the default fields).
|
||||
|
||||

|
||||
_RichText link with custom fields_
|
||||
|
||||
**`upload.collections[collection-name].fields`**
|
||||
|
||||
This allows [fields](/docs/fields/overview) to be saved as meta data on an upload field inside the Rich Text Editor. When this is present, the fields will render inside a modal that can be opened by clicking the "edit" button on the upload element.
|
||||
|
||||

|
||||
_RichText field using the upload element_
|
||||
|
||||

|
||||
_RichText upload element modal displaying fields from the config_
|
||||
|
||||
**`rtl`**
|
||||
|
||||
Override the default text direction of the Admin panel for this field. Set to `true` to force right-to-left text direction.
|
||||
|
||||
### Relationship element
|
||||
|
||||
The built-in `relationship` element is a powerful way to reference other Documents directly within your Rich Text editor.
|
||||
|
||||
### Upload element
|
||||
|
||||
Similar to the `relationship` element, the `upload` element is a user-friendly way to reference [Upload-enabled collections](/docs/upload/overview) with a UI specifically designed for media / image-based uploads.
|
||||
### Linked Documents
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Tip:</strong>
|
||||
@@ -132,226 +51,25 @@ Similar to the `relationship` element, the `upload` element is a user-friendly w
|
||||
|
||||
Relationship and Upload elements are populated dynamically into your Rich Text field' content. Within the REST and Local APIs, any present RichText `relationship` or `upload` elements will respect the `depth` option that you pass, and will be populated accordingly. In GraphQL, each `richText` field accepts an argument of `depth` for you to utilize.
|
||||
|
||||
### TextAlign element
|
||||
|
||||
Text Alignment is not included by default and can be added to a Rich Text Editor by adding `textAlign` to the list of elements. TextAlign will alter the existing element to include a new `textAlign` field in the resulting JSON. This field can be used in combination with other elements and leaves to position content to the left, center or right.
|
||||
|
||||
### Specifying which elements and leaves to allow
|
||||
|
||||
To specify which default elements or leaves should be allowed to be used for this field, define arrays that contain string names for each element or leaf you wish to enable. To specify a custom element or leaf, pass an object with all corresponding properties as outlined below. View the [example](#example) to reference how this all works.
|
||||
|
||||
### Building custom elements and leaves
|
||||
|
||||
You can design and build your own Slate elements and leaves to extend the editor with your own functionality. To do so, first start by reading the [SlateJS documentation](https://docs.slatejs.org/) and looking at the [Slate examples](https://www.slatejs.org/examples/richtext) to familiarize yourself with the SlateJS editor as a whole.
|
||||
|
||||
Once you're up to speed with the general concepts involved, you can pass in your own elements and leaves to your field's admin config.
|
||||
|
||||
**Both custom elements and leaves are defined via the following config:**
|
||||
|
||||
| Property | Description |
|
||||
| --------------- | ---------------------------------------------------------- |
|
||||
| **`name`** \* | The default name to be used as a `type` for this element. |
|
||||
| **`Button`** \* | A React component to be rendered in the Rich Text toolbar. |
|
||||
| **`plugins`** | An array of plugins to provide to the Rich Text editor. |
|
||||
| **`type`** | A type that overrides the default type used by `name` |
|
||||
|
||||
Custom `Element`s also require the `Element` property set to a React component to be rendered as the `Element` within the rich text editor itself.
|
||||
|
||||
Custom `Leaf` objects follow a similar pattern but require you to define the `Leaf` property instead.
|
||||
|
||||
Specifying custom `Type`s let you extend your custom elements by adding additional fields to your JSON object.
|
||||
|
||||
### Example
|
||||
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { lexicalEditor } from '@payloadcms/richtext-lexical';
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
export const Pages: CollectionConfig = {
|
||||
slug: 'pages',
|
||||
fields: [
|
||||
{
|
||||
name: 'content',
|
||||
type: 'richText',
|
||||
editor: lexicalEditor({
|
||||
features: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'bold', 'italic', 'underline', 'strikethrough', 'link', 'blockquote', 'ul', 'ol', 'code'],
|
||||
}),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
name: 'content', // required
|
||||
type: 'richText', // required
|
||||
defaultValue: [
|
||||
{
|
||||
children: [{ text: 'Here is some default content for this field' }],
|
||||
},
|
||||
],
|
||||
required: true,
|
||||
admin: {
|
||||
elements: [
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'link',
|
||||
'blockquote',
|
||||
{
|
||||
name: 'cta',
|
||||
Button: CustomCallToActionButton,
|
||||
Element: CustomCallToActionElement,
|
||||
plugins: [
|
||||
// any plugins that are required by this element go here
|
||||
],
|
||||
},
|
||||
],
|
||||
leaves: [
|
||||
'bold',
|
||||
'italic',
|
||||
{
|
||||
name: 'highlight',
|
||||
Button: CustomHighlightButton,
|
||||
Leaf: CustomHighlightLeaf,
|
||||
plugins: [
|
||||
// any plugins that are required by this leaf go here
|
||||
],
|
||||
},
|
||||
],
|
||||
link: {
|
||||
// Inject your own fields into the Link element
|
||||
fields: [
|
||||
{
|
||||
name: 'rel',
|
||||
label: 'Rel Attribute',
|
||||
type: 'select',
|
||||
hasMany: true,
|
||||
options: ['noopener', 'noreferrer', 'nofollow'],
|
||||
},
|
||||
],
|
||||
},
|
||||
upload: {
|
||||
collections: {
|
||||
media: {
|
||||
fields: [
|
||||
// any fields that you would like to save
|
||||
// on an upload element in the `media` collection
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
For more examples regarding how to define your own elements and leaves, check out the example [`RichText` field](https://github.com/payloadcms/public-demo/blob/master/src/fields/hero.ts) within the Public Demo source code.
|
||||
|
||||
### Generating HTML
|
||||
|
||||
As the Rich Text field saves its content in a JSON format, you'll need to render it as HTML yourself. Here is an example for how to generate JSX / HTML from Rich Text content:
|
||||
|
||||
```ts
|
||||
import React, { Fragment } from "react";
|
||||
import escapeHTML from "escape-html";
|
||||
import { Text } from "slate";
|
||||
|
||||
const serialize = (children) =>
|
||||
children.map((node, i) => {
|
||||
if (Text.isText(node)) {
|
||||
let text = (
|
||||
<span dangerouslySetInnerHTML={{ __html: escapeHTML(node.text) }} />
|
||||
);
|
||||
|
||||
if (node.bold) {
|
||||
text = <strong key={i}>{text}</strong>;
|
||||
}
|
||||
|
||||
if (node.code) {
|
||||
text = <code key={i}>{text}</code>;
|
||||
}
|
||||
|
||||
if (node.italic) {
|
||||
text = <em key={i}>{text}</em>;
|
||||
}
|
||||
|
||||
// Handle other leaf types here...
|
||||
|
||||
return <Fragment key={i}>{text}</Fragment>;
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (node.type) {
|
||||
case "h1":
|
||||
return <h1 key={i}>{serialize(node.children)}</h1>;
|
||||
// Iterate through all headings here...
|
||||
case "h6":
|
||||
return <h6 key={i}>{serialize(node.children)}</h6>;
|
||||
case "blockquote":
|
||||
return <blockquote key={i}>{serialize(node.children)}</blockquote>;
|
||||
case "ul":
|
||||
return <ul key={i}>{serialize(node.children)}</ul>;
|
||||
case "ol":
|
||||
return <ol key={i}>{serialize(node.children)}</ol>;
|
||||
case "li":
|
||||
return <li key={i}>{serialize(node.children)}</li>;
|
||||
case "link":
|
||||
return (
|
||||
<a href={escapeHTML(node.url)} key={i}>
|
||||
{serialize(node.children)}
|
||||
</a>
|
||||
);
|
||||
|
||||
default:
|
||||
return <p key={i}>{serialize(node.children)}</p>;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
<Banner>
|
||||
<strong>Note:</strong>
|
||||
<br />
|
||||
The above example is for how to render to JSX, although for plain HTML the pattern is similar.
|
||||
Just remove the JSX and return HTML strings instead!
|
||||
</Banner>
|
||||
|
||||
### Built-in SlateJS Plugins
|
||||
|
||||
Payload comes with a few built-in SlateJS plugins which can be extended to make developing your own elements and leaves a bit easier. They will be documented here over time.
|
||||
|
||||
#### `shouldBreakOutOnEnter`
|
||||
|
||||
Payload's built-in heading elements all allow a "hard return" to "break out" of the currently active element. For example, if you hit `enter` while typing an `h1`, the `h1` will be "broken out of" and you'll be able to continue writing as the default paragraph element.
|
||||
|
||||
If you want to utilize this functionality within your own custom elements, you can do so by adding a custom plugin to your `element` like the following "large body" element example:
|
||||
|
||||
`customLargeBodyElement.js`:
|
||||
|
||||
```ts
|
||||
import Button from './Button'
|
||||
import Element from './Element'
|
||||
import withLargeBody from './plugin'
|
||||
|
||||
export default {
|
||||
name: 'large-body',
|
||||
Button,
|
||||
Element,
|
||||
plugins: [
|
||||
(incomingEditor) => {
|
||||
const editor = incomingEditor
|
||||
const { shouldBreakOutOnEnter } = editor
|
||||
|
||||
editor.shouldBreakOutOnEnter = (element) =>
|
||||
element.type === 'large-body' ? true : shouldBreakOutOnEnter(element)
|
||||
|
||||
return editor
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
Above, you can see that we are creating a custom SlateJS element with a name of `large-body`. This might render a slightly larger body copy on the frontend of your app(s). We pass it a name, button, and element—but additionally, we pass it a `plugins` array containing a single SlateJS plugin.
|
||||
|
||||
The plugin itself extends Payload's built-in `shouldBreakOutOnEnter` Slate function to add its own element name to the list of elements that should "break out" when the `enter` key is pressed.
|
||||
|
||||
### TypeScript
|
||||
|
||||
If you are building your own custom Rich Text elements or leaves, you may benefit from importing the following types:
|
||||
|
||||
```ts
|
||||
import type { RichTextCustomElement, RichTextCustomLeaf } from 'payload/types'
|
||||
```
|
||||
|
||||
@@ -3,7 +3,7 @@ title: Live Preview
|
||||
label: Overview
|
||||
order: 10
|
||||
desc: With Live Preview you can render your front-end application directly within the Admin panel. Your changes take effect as you type. No save needed.
|
||||
keywords: 'live preview', 'preview', 'live', 'iframe', 'iframe preview', 'visual editing', 'design'
|
||||
keywords: live preview, preview, live, iframe, iframe preview, visual editing, design
|
||||
---
|
||||
|
||||
**With Live Preview you can render your front-end application directly within the Admin panel. As you type, your changes take effect in real-time. No need to save a draft or publish your changes.**
|
||||
|
||||
@@ -2,9 +2,23 @@
|
||||
title: Rendering Rich Text on your Frontend
|
||||
label: Rendering on Frontend
|
||||
order: 20
|
||||
desc: NEED TO WRITE
|
||||
keywords: NEED TO WRITE
|
||||
desc: Learn how to render rich text data from your database on your frontend.
|
||||
keywords: rich text, rendering, frontend, react, javascript, node, express, cms, headless, content management system, documentation
|
||||
---
|
||||
|
||||
Give an example for how to render JSX on the frontend
|
||||
In the future, we will add docs that show how to add virtual fields for HTML / MDX transforming
|
||||
The rich text field saves data as JSON in the database. This allows you to convert the data into any format you need, including JSX or HTML. To serizalize your data, you will need to write a function that recursively renders the JSON data into HTML.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
|
||||
```ts
|
||||
|
||||
// example here
|
||||
|
||||
```
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Note:</strong>
|
||||
If you are using Slate editor for rich text, the structure of your JSON data will look different. See the [Slate docs](/docs/rich-text/slate#generating-html) for more details on how to serialize JSON data from Slate.
|
||||
</Banner>
|
||||
@@ -2,10 +2,123 @@
|
||||
title: Lexical Rich Text
|
||||
label: Lexical
|
||||
order: 30
|
||||
desc: NEED TO WRITE
|
||||
keywords: NEED TO WRITE
|
||||
desc: Lexical is a powerful, extensible rich text editor created by Meta.
|
||||
keywords: rich text, lexical, meta, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
|
||||
---
|
||||
|
||||
Talk about the reasons why we are using Lexical, what it does well, and where we plan to go in the future
|
||||
Show a code snippet for how to install it
|
||||
Show how to configure it, with options
|
||||
The new Lexical Rich Text Editor an incredibly powerful, extensible rich text editor created by Meta. It is the recommended rich text editor for new projects as of Payload 2.0.0. It is also the default rich text editor for new projects created with `create-payload-app`.
|
||||
|
||||
Lexical is a great choice for projects that need a rich text editor that is easy to use, but also extensible and customizable.
|
||||
|
||||
<LightDarkImage
|
||||
srcLight="https://cms.payloadcms.com/media/lexical-rich-text-field.png"
|
||||
srcDark="https://cms.payloadcms.com/media/lexical-rich-text-field-dark.png"
|
||||
alt="Shows a Rich Text field in the Payload admin panel"
|
||||
caption="A screenshot of the Rich Text field in the Payload admin panel"
|
||||
/>
|
||||
|
||||
## Installation
|
||||
|
||||
To define Lexical as your rich text editor, you can pass it into the `editor` property in your `payload.config.ts` file. This will install Lexical for all fields that use the `richText` type. You can also pass in any options that Lexical accepts, which will be used by default for all instances of the rich text editor.
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { LexicalEditor } from '@payloadcms/richtext-lexical'
|
||||
|
||||
export default buildConfig({
|
||||
editor: LexicalEditor({
|
||||
// pass in your options here
|
||||
}),
|
||||
|
||||
// the rest of your config
|
||||
})
|
||||
```
|
||||
|
||||
### Override at the field level
|
||||
|
||||
You can customize Lexical on a field-by-field basis by passing in an editor to the `editor` property on the field. This will override the rich text editor configuration that is installed at the top level.
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { LexicalEditor } from '@payloadcms/richtext-lexical'
|
||||
|
||||
export Example: CollectionConfig = {
|
||||
slug: 'example',
|
||||
fields: [
|
||||
{
|
||||
name: 'body',
|
||||
type: 'richText',
|
||||
editor: LexicalEditor({
|
||||
// pass in your field-specific options here
|
||||
}),
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
You can pass in the following options to configure Lexical:
|
||||
|
||||
| Option | Description |
|
||||
| --- | --- |
|
||||
| `features` | Features are the entry point for adding functionality into the rich text editor. [More](#features) |
|
||||
| `blocks` | Pass in an array of [Blocks](/docs/fields/blocks) that can be added inline inside the editor. |
|
||||
| `lexical` | An object of Lexical-specific options for changing the editor settings like theming. |
|
||||
|
||||
### Features
|
||||
|
||||
Lexical is built on a "feature" system that allows you to add functionality to the editor. This is done by passing in a `features` array to the `LexicalEditor` function. Each feature is an object with a `name` and `options` property. The `name` property is the name of the feature, and the `options` property is an object of options that will be passed into the feature.
|
||||
|
||||
```ts
|
||||
LexicalEditor({
|
||||
features: [],
|
||||
})
|
||||
```
|
||||
### Blocks
|
||||
|
||||
Talk about blocks
|
||||
|
||||
### Example
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { LexicalEditor } from '@payloadcms/richtext-lexical'
|
||||
import { CtaBlock } from './blocks/CtaBlock'
|
||||
import { FormBlock } from './blocks/FormBlock'
|
||||
|
||||
export default buildConfig({
|
||||
editor: LexicalEditor({
|
||||
features: [
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'paragraph',
|
||||
'link',
|
||||
'bold',
|
||||
'italic',
|
||||
'underline',
|
||||
// ...
|
||||
],
|
||||
blocks: [
|
||||
CtaBlock,
|
||||
FormBlock,
|
||||
],
|
||||
}),
|
||||
|
||||
// the rest of your config
|
||||
|
||||
})
|
||||
```
|
||||
|
||||
### Lexical Options
|
||||
|
||||
Talk about lexical specific options
|
||||
|
||||
### Creating Custom Features
|
||||
|
||||
Talk about creating custom features
|
||||
|
||||
### Rendering on the frontend
|
||||
|
||||
Link to frontend page lexical example
|
||||
@@ -1,16 +1,55 @@
|
||||
---
|
||||
title: Overview
|
||||
label: Rich Text Field
|
||||
label: Rich Text Editor
|
||||
order: 10
|
||||
desc: NEED TO WRITE
|
||||
keywords: NEED TO WRITE
|
||||
desc: Payload offers two rich text editors for writing dynamic content in your CMS, and provides an adapter pattern for adding your own.
|
||||
keywords: rich text, adapter, slate, lexical, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
|
||||
---
|
||||
|
||||
TODO:
|
||||
Payload provides a rich text editor adapter pattern that allows you to use any rich text editor you want. Out of the box, Payload comes with two rich text editors, [Lexical](/docs/rich-text/lexical) and [Slate](/docs/rich-text/slate) but you can also install your own.
|
||||
|
||||
<Banner>
|
||||
**As of 2.0.0**, [Lexical](/docs/rich-text/lexical) is now the recommended rich text editor for new projects. Slate is still supported for legacy projects, but we are moving to Lexical from here on out which offers more features. For new projects as of 2.0.0, we recommend using Lexical. For existing projects, use Slate.
|
||||
</Banner>
|
||||
|
||||
## Installation
|
||||
|
||||
To define a rich text editor to be used across your entire project, you can pass it into the `editor` property in your `payload.config.ts` file. This will install the rich text editor for all fields that use the `richText` type. You can also pass in any options that the rich text editor accepts, which will be used by default for all instances of the rich text editor.
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { lexicalEditor } from '@payloadcms/richtext-lexical'
|
||||
|
||||
export default buildConfig({
|
||||
editor: LexicalEditor({
|
||||
// pass in your options here
|
||||
}),
|
||||
|
||||
// the rest of your config
|
||||
})
|
||||
```
|
||||
|
||||
### Override at the field level
|
||||
|
||||
You can customize the rich text editor on a field-by-field basis by passing in an editor to the `editor` property on the field. This will override the rich text editor configuration that is installed at the top level.
|
||||
|
||||
Note: It is **not recommended** to use more than one rich text editor in your project. This will result in multiple rich text editors being loaded on the page, which will slow down your CMS and increase the bundle size of your project.
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { LexicalEditor } from '@payloadcms/richtext-lexical'
|
||||
|
||||
export Example: CollectionConfig = {
|
||||
slug: 'example',
|
||||
fields: [
|
||||
{
|
||||
name: 'body',
|
||||
type: 'richText',
|
||||
editor: LexicalEditor({
|
||||
// pass in your field-specific options here
|
||||
}),
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
- Talk about how Payload supports two rich text editors, and they work on an "adapter" pattern, which means you need to install the one you want to use separately and pass it to config
|
||||
- Talk about how Slate is still supported for legacy projects, but we are moving to Lexical from here on out which offers more features
|
||||
- For new projects as of 2.0, use Lexical
|
||||
- For existing projects, use Slate
|
||||
- Probably move some of the more complex docs from Fields -> Rich Text over to this set of docs
|
||||
- Show how you can install an editor at the top level, or override on a field-by-field basis (not recommended, no reason to have 2 editors installed. Lots of JS loaded)
|
||||
@@ -2,8 +2,341 @@
|
||||
title: Slate Rich Text
|
||||
label: Slate
|
||||
order: 40
|
||||
desc: NEED TO WRITE
|
||||
keywords: NEED TO WRITE
|
||||
desc: Slate is a is a lightweight, customizable rich text editor that is built for React, and is included in Payload.
|
||||
keywords: rich text, slate, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
|
||||
---
|
||||
|
||||
Recreate a similar approach to Lexical here
|
||||
<Banner>As of 2.0.0, [Lexical](./lexical.mdx) has replaces Slate as the preferred rich text editor. For new projects, we recommend using the Lexical editor. For existing projects, you can continue to use Slate.</Banner>
|
||||
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/richtext.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/richtext-dark.png"
|
||||
alt="Shows a Rich Text field in the Payload admin panel"
|
||||
caption="Admin panel screenshot of a Slate Rich Text field"
|
||||
/>
|
||||
|
||||
The Admin component is built on the powerful [`slatejs`](https://docs.slatejs.org/) editor and is meant to be as extensible and customizable as possible.
|
||||
|
||||
## Editor config
|
||||
|
||||
The Slate editor can be configured by passing in an object to the `editor` property of your `payload.config.ts` file. From there, you can pass in any options that the Slate editor accepts with the `admin` object.
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { SlateEditor } from '@payloadcms/richtext-slate'
|
||||
|
||||
export default buildConfig({
|
||||
editor: SlateEditor({
|
||||
admin: {
|
||||
// pass in your editor options here
|
||||
}
|
||||
}),
|
||||
|
||||
// the rest of your config
|
||||
|
||||
})
|
||||
```
|
||||
|
||||
The `admin` object accepts the following properties:
|
||||
|
||||
| Option | Description |
|
||||
| --- | --- |
|
||||
| `placeholder` | Set this property to define a placeholder string in the text input. |
|
||||
| `elements` | The `elements` property is used to specify which built-in or custom [SlateJS elements](https://docs.slatejs.org/concepts/02-nodes#element) should be made available to the field within the admin panel. |
|
||||
| `leaves` | The `leaves` property specifies built-in or custom [SlateJS leaves](https://docs.slatejs.org/concepts/08-rendering#leaves) to be enabled within the Admin panel. |
|
||||
| `link.fields` | This allows [fields](/docs/fields/overview) to be saved as extra fields on a link inside the editor. When this is present, the fields will render inside a modal that can be opened by clicking the "edit" button on the link element. [More](#links)|
|
||||
| `rtl` | Override the default text direction of the Admin panel for this field. Set to `true` to force right-to-left text direction. |
|
||||
| `hideGutter` | Set this property to `true` to hide this field's gutter within the admin panel. The field gutter is rendered as a vertical line and padding, but often if this field is nested within a Group, Block, or Array, you may want to hide the gutter. |
|
||||
|
||||
### Default Elements
|
||||
|
||||
The default `elements` available in the Slate editor are:
|
||||
|
||||
- `h1`
|
||||
- `h2`
|
||||
- `h3`
|
||||
- `h4`
|
||||
- `h5`
|
||||
- `h6`
|
||||
- `blockquote`
|
||||
- `link`
|
||||
- `ol`
|
||||
- `ul`
|
||||
- `textAlign`
|
||||
- `indent`
|
||||
- [`relationship`](#relationship-element)
|
||||
- [`upload`](#upload-element)
|
||||
- [`textAlign`](#text-align)
|
||||
|
||||
### Default Leaves
|
||||
|
||||
The default `leaves` available in the Slate editor are:
|
||||
|
||||
- `bold`
|
||||
- `code`
|
||||
- `italic`
|
||||
- `strikethrough`
|
||||
- `underline`
|
||||
|
||||
### Custom Link Fields
|
||||
|
||||
You can define which [fields](/docs/fields/overview) to show in the admin panel when adding links in the Rich Text Editor by passing `fields` to the `link` element. When this is present, the fields will render inside a modal that can be opened by clicking the "edit" button on the link element.
|
||||
|
||||

|
||||
_RichText link with custom fields_
|
||||
|
||||
`link.fields` may either be an array of fields (in which case all fields defined in it will be appended below the default fields) or a function that accepts the default fields as only argument and returns an array defining the entirety of fields to be used (thus providing a mechanism of overriding the default fields).
|
||||
|
||||
### Relationship element
|
||||
|
||||
The built-in `relationship` element is a powerful way to reference other Documents directly within your Rich Text editor.
|
||||
|
||||
### Upload element
|
||||
|
||||
Similar to the `relationship` element, the `upload` element is a user-friendly way to reference [Upload-enabled collections](/docs/upload/overview) with a UI specifically designed for media / image-based uploads.
|
||||
|
||||
**`upload.collections[collection-name].fields`**
|
||||
|
||||
This allows [fields](/docs/fields/overview) to be saved as meta data on an upload field inside the Rich Text Editor. When this is present, the fields will render inside a modal that can be opened by clicking the "edit" button on the upload element.
|
||||
|
||||

|
||||
_RichText field using the upload element_
|
||||
|
||||

|
||||
_RichText upload element modal displaying fields from the config_
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Tip:</strong>
|
||||
<br />
|
||||
Collections are automatically allowed to be selected within the Rich Text relationship and upload
|
||||
elements by default. If you want to disable a collection from being able to be referenced in Rich
|
||||
Text fields, set the collection admin options of <strong>enableRichTextLink</strong> and{' '}
|
||||
<strong>enableRichTextRelationship</strong> to false.
|
||||
</Banner>
|
||||
|
||||
Relationship and Upload elements are populated dynamically into your Rich Text field' content. Within the REST and Local APIs, any present RichText `relationship` or `upload` elements will respect the `depth` option that you pass, and will be populated accordingly. In GraphQL, each `richText` field accepts an argument of `depth` for you to utilize.
|
||||
|
||||
### TextAlign element
|
||||
|
||||
Text Alignment is not included by default and can be added to a Rich Text Editor by adding `textAlign` to the list of elements. TextAlign will alter the existing element to include a new `textAlign` field in the resulting JSON. This field can be used in combination with other elements and leaves to position content to the left, center or right.
|
||||
|
||||
### Specifying which elements and leaves to allow
|
||||
|
||||
To specify which default elements or leaves should be allowed to be used for this field, define arrays that contain string names for each element or leaf you wish to enable. To specify a custom element or leaf, pass an object with all corresponding properties as outlined below. View the [example](#example) to reference how this all works.
|
||||
|
||||
### Building custom elements and leaves
|
||||
|
||||
You can design and build your own Slate elements and leaves to extend the editor with your own functionality. To do so, first start by reading the [SlateJS documentation](https://docs.slatejs.org/) and looking at the [Slate examples](https://www.slatejs.org/examples/richtext) to familiarize yourself with the SlateJS editor as a whole.
|
||||
|
||||
Once you're up to speed with the general concepts involved, you can pass in your own elements and leaves to your field's admin config.
|
||||
|
||||
**Both custom elements and leaves are defined via the following config:**
|
||||
|
||||
| Property | Description |
|
||||
| --------------- | ---------------------------------------------------------- |
|
||||
| **`name`** \* | The default name to be used as a `type` for this element. |
|
||||
| **`Button`** \* | A React component to be rendered in the Rich Text toolbar. |
|
||||
| **`plugins`** | An array of plugins to provide to the Rich Text editor. |
|
||||
| **`type`** | A type that overrides the default type used by `name` |
|
||||
|
||||
Custom `Element`s also require the `Element` property set to a React component to be rendered as the `Element` within the rich text editor itself.
|
||||
|
||||
Custom `Leaf` objects follow a similar pattern but require you to define the `Leaf` property instead.
|
||||
|
||||
Specifying custom `Type`s let you extend your custom elements by adding additional fields to your JSON object.
|
||||
|
||||
### Example
|
||||
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { SlateEditor } from '@payloadcms/richtext-slate'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
name: 'content', // required
|
||||
type: 'richText', // required
|
||||
defaultValue: [
|
||||
{
|
||||
children: [{ text: 'Here is some default content for this field' }],
|
||||
},
|
||||
],
|
||||
required: true,
|
||||
editor: SlateEditor({
|
||||
elements: [
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'link',
|
||||
'blockquote',
|
||||
{
|
||||
name: 'cta',
|
||||
Button: CustomCallToActionButton,
|
||||
Element: CustomCallToActionElement,
|
||||
plugins: [
|
||||
// any plugins that are required by this element go here
|
||||
],
|
||||
},
|
||||
],
|
||||
leaves: [
|
||||
'bold',
|
||||
'italic',
|
||||
{
|
||||
name: 'highlight',
|
||||
Button: CustomHighlightButton,
|
||||
Leaf: CustomHighlightLeaf,
|
||||
plugins: [
|
||||
// any plugins that are required by this leaf go here
|
||||
],
|
||||
},
|
||||
],
|
||||
link: {
|
||||
// Inject your own fields into the Link element
|
||||
fields: [
|
||||
{
|
||||
name: 'rel',
|
||||
label: 'Rel Attribute',
|
||||
type: 'select',
|
||||
hasMany: true,
|
||||
options: ['noopener', 'noreferrer', 'nofollow'],
|
||||
},
|
||||
],
|
||||
},
|
||||
upload: {
|
||||
collections: {
|
||||
media: {
|
||||
fields: [
|
||||
// any fields that you would like to save
|
||||
// on an upload element in the `media` collection
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
For more examples regarding how to define your own elements and leaves, check out the example [`RichText` field](https://github.com/payloadcms/public-demo/blob/master/src/fields/hero.ts) within the Public Demo source code.
|
||||
|
||||
### Generating HTML
|
||||
|
||||
As the Rich Text field saves its content in a JSON format, you'll need to render it as HTML yourself. Here is an example for how to generate JSX / HTML from Slate Rich Text content:
|
||||
|
||||
```ts
|
||||
import React, { Fragment } from "react";
|
||||
import escapeHTML from "escape-html";
|
||||
import { Text } from "slate";
|
||||
|
||||
const serialize = (children) =>
|
||||
children.map((node, i) => {
|
||||
if (Text.isText(node)) {
|
||||
let text = (
|
||||
<span dangerouslySetInnerHTML={{ __html: escapeHTML(node.text) }} />
|
||||
);
|
||||
|
||||
if (node.bold) {
|
||||
text = <strong key={i}>{text}</strong>;
|
||||
}
|
||||
|
||||
if (node.code) {
|
||||
text = <code key={i}>{text}</code>;
|
||||
}
|
||||
|
||||
if (node.italic) {
|
||||
text = <em key={i}>{text}</em>;
|
||||
}
|
||||
|
||||
// Handle other leaf types here...
|
||||
|
||||
return <Fragment key={i}>{text}</Fragment>;
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (node.type) {
|
||||
case "h1":
|
||||
return <h1 key={i}>{serialize(node.children)}</h1>;
|
||||
// Iterate through all headings here...
|
||||
case "h6":
|
||||
return <h6 key={i}>{serialize(node.children)}</h6>;
|
||||
case "blockquote":
|
||||
return <blockquote key={i}>{serialize(node.children)}</blockquote>;
|
||||
case "ul":
|
||||
return <ul key={i}>{serialize(node.children)}</ul>;
|
||||
case "ol":
|
||||
return <ol key={i}>{serialize(node.children)}</ol>;
|
||||
case "li":
|
||||
return <li key={i}>{serialize(node.children)}</li>;
|
||||
case "link":
|
||||
return (
|
||||
<a href={escapeHTML(node.url)} key={i}>
|
||||
{serialize(node.children)}
|
||||
</a>
|
||||
);
|
||||
|
||||
default:
|
||||
return <p key={i}>{serialize(node.children)}</p>;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
<Banner>
|
||||
<strong>Note:</strong>
|
||||
<br />
|
||||
The above example is for how to render to JSX, although for plain HTML the pattern is similar.
|
||||
Just remove the JSX and return HTML strings instead!
|
||||
</Banner>
|
||||
|
||||
### Built-in SlateJS Plugins
|
||||
|
||||
Payload comes with a few built-in SlateJS plugins which can be extended to make developing your own elements and leaves a bit easier. They will be documented here over time.
|
||||
|
||||
#### `shouldBreakOutOnEnter`
|
||||
|
||||
Payload's built-in heading elements all allow a "hard return" to "break out" of the currently active element. For example, if you hit `enter` while typing an `h1`, the `h1` will be "broken out of" and you'll be able to continue writing as the default paragraph element.
|
||||
|
||||
If you want to utilize this functionality within your own custom elements, you can do so by adding a custom plugin to your `element` like the following "large body" element example:
|
||||
|
||||
`customLargeBodyElement.js`:
|
||||
|
||||
```ts
|
||||
import Button from './Button'
|
||||
import Element from './Element'
|
||||
import withLargeBody from './plugin'
|
||||
|
||||
export default {
|
||||
name: 'large-body',
|
||||
Button,
|
||||
Element,
|
||||
plugins: [
|
||||
(incomingEditor) => {
|
||||
const editor = incomingEditor
|
||||
const { shouldBreakOutOnEnter } = editor
|
||||
|
||||
editor.shouldBreakOutOnEnter = (element) =>
|
||||
element.type === 'large-body' ? true : shouldBreakOutOnEnter(element)
|
||||
|
||||
return editor
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
Above, you can see that we are creating a custom SlateJS element with a name of `large-body`. This might render a slightly larger body copy on the frontend of your app(s). We pass it a name, button, and element—but additionally, we pass it a `plugins` array containing a single SlateJS plugin.
|
||||
|
||||
The plugin itself extends Payload's built-in `shouldBreakOutOnEnter` Slate function to add its own element name to the list of elements that should "break out" when the `enter` key is pressed.
|
||||
|
||||
### TypeScript
|
||||
|
||||
If you are building your own custom Rich Text elements or leaves, you may benefit from importing the following types:
|
||||
|
||||
```ts
|
||||
import type { RichTextCustomElement, RichTextCustomLeaf } from 'payload/types'
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user