Simplify your stack and build anything. Or everything.
Build tomorrow’s web with a modern solution you truly own.
Code-based nature means you can build on top of it to power anything.
It’s time to take back your content infrastructure.

Slate JS / Rich Text and paragraphs

default discord avatar
_jeangabriellast year
1

Hey! Just looking at the demo CMS on the website and checking out how rich text is formatted on the JSON output.



One thing I can't work out is why there are no elements for paragraphs i.e.

type: "paragraph"

for each entered paragraph? The default elements in the docs mention h1 to h6 and other elements, but no p tags.



I can't seem to decipher the code on the demo repository on Github either on how paragraph elements are being created.



How is this managed / converted?



Thanks so much!

  • discord user avatar
    tylandavis
    last year

    Hi @_jeangabriel, but here's a quick explanation of how it's handled:



    The elements shown in the docs example (

    https://payloadcms.com/docs/fields/rich-text#example

    ) are any formats that are not the default. Technically, your default format could be anything, but you can think of it as a

    <p>

    tag by default.



    Below is an example of how we would generate the HTML on the frontend for Rich Text fields:



    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>
          );
      }
    });


    This is a

    switch

    statement that check the

    case

    of each node. Once it finds it, it wraps it in the correct HTML tag. Then, it runs the function again to the children of that node. This method iterates through any possible cases you define, and then if it doesn't find a specific case, it return the default case, which in the code above is a

    <p>

    element.

Star on GitHub

Star

Chat on Discord

Discord

online

Can't find what you're looking for?

Get dedicated engineering support directly from the Payload team..