Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[StoryblokRichText] Nested <p> tag inside of lists. #1351

Open
1 task done
christopher-ha opened this issue Feb 21, 2025 · 3 comments
Open
1 task done

[StoryblokRichText] Nested <p> tag inside of lists. #1351

christopher-ha opened this issue Feb 21, 2025 · 3 comments
Labels
has-workaround [Issue] Temporary solutions available. p2-nice-to-have [Priority] Lower priority, beneficial enhancements that are not urgent.

Comments

@christopher-ha
Copy link

Describe the issue you're facing

Image

You can see here that typing on a list element generates a new paragraph tag, when the resolver should skip over rendering this. This is causing issues in my blog where if I have styling specifically for paragraphs like how much width it will take up, it gets applied inside of the list element and really messes up the layout.

The ideal behaviour of this is that the resolver does not render the nested paragraph tag and just places the content of it inside of the ul, ol, etc.

Apparently the Astro library doesn't do this?

Image

No reproduction link since it's on my client's repository.

Reproduction

https://localhost:3000

Steps to reproduce

Create an ordered list an unordered list on Storyblok and render it using the rich text resolver. You will see in the console log, it's rendering the nested structure.

It happens on both the richTextResolver and also the new component.

System Info

System:
    OS: macOS 15.0.1
    CPU: (10) arm64 Apple M1 Max
    Memory: 53.55 MB / 32.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.14.0 - ~/.nvm/versions/node/v20.14.0/bin/node
    Yarn: 1.22.22 - ~/.nvm/versions/node/v20.14.0/bin/yarn
    npm: 10.7.0 - ~/.nvm/versions/node/v20.14.0/bin/npm
    pnpm: 10.2.1 - ~/.nvm/versions/node/v20.14.0/bin/pnpm
    bun: 1.0.0 - ~/.bun/bin/bun
  Browsers:
    Chrome: 133.0.6943.127
    Safari: 18.0.1

Used Package Manager

npm

Error logs (Optional)

No response

Validations

@christopher-ha christopher-ha added pending-author [Issue] Awaiting further information or action from the issue author pending-triage [Issue] Ticket is pending to be prioritised labels Feb 21, 2025
@alvarosabu
Copy link
Contributor

alvarosabu commented Feb 25, 2025

Hi @christopher-ha thanks for opening this ticket.

So the reason why the p tag is rendered inside the list items li is that the TipTap editor used by Storyblok App generates the node structure of the image you added to the ticket:

{
      type: 'bullet_list',
      content: [
        {
          type: 'list_item',
          content: [
            {
              type: 'paragraph',
              content: [
                {
                  text: 'Bull',
                  type: 'text',
                  marks: [{ type: 'italic' }],
                },
                {
                  text: 'et 1',
                  type: 'text',
                  marks: [{ type: 'bold' }],
                },
              ],
            },
          ],
        },
        {
          type: 'list_item',
          content: [
            {
              type: 'paragraph',
              content: [{ text: 'Bullet 2', type: 'text' }],
            },
          ],
        },
        {
          type: 'list_item',
          content: [
            {
              type: 'paragraph',
              content: [
                {
                  text: 'Bullet 3',
                  type: 'text',
                  marks: [{ type: 'styled', attrs: { class: 'css-class' } }],
                },
              ],
            },
          ],
        },
        { type: 'list_item', content: [{ type: 'paragraph' }] },
      ],
    },

Having a p inside a li is semantically correct, the <li> HTML element allows Flow Content. Since <p> is part of flow content, placing <p> inside <li> is valid. Although I understand that might not be ideal for the UI or the CSS classes so here is a workaround:

  resolvers: {
    [BlockTypes.LIST_ITEM]: (node: StoryblokRichTextNode<string>) => {
      const text = node.content[0].content[0].text; // Gets the text inside of the p tag
      return `<li>${text}</li>`;
    },
  },

By overwriting the resolver, you now skip the p tag, be aware that if you want to show some mark types like bold, or italic, you might need to tweak it further.

Hope that helps

@alvarosabu alvarosabu added has-workaround [Issue] Temporary solutions available. and removed pending-author [Issue] Awaiting further information or action from the issue author labels Feb 25, 2025
@alvarosabu
Copy link
Contributor

alvarosabu commented Feb 25, 2025

Update: since the workaround above covers usage with the vanilla @storyblok/richtext if it's important to maintain the markTypes inside the list item element for React, the workaround is not that trivial

const { render } = richTextResolver({
    renderFn: React.createElement,
    keyedResolvers: true,
  });

  const options: StoryblokRichTextOptions<ReactElement> = {
    renderFn: React.createElement,
    resolvers: {
      [BlockTypes.LIST_ITEM]: (node: StoryblokRichTextNode<string>) => {
        return render(node.content?.[0]);
      },
    },
    keyedResolvers: true,
  };

  const html = richTextResolver(
    options,
  ).render(story.content.richtext);

Here we can use the render function returned by the richTextResolver to render inside the resolver overwrite, but is not ideal to initiate twice the method so a possible improvement we can add to resolvers is returning the render function along with the node.

[BlockTypes.LIST_ITEM]: (node: StoryblokRichTextNode<string>, render) => {
    return render(node.content?.[0]);
  },

I will work on it.

@alvarosabu alvarosabu added p2-nice-to-have [Priority] Lower priority, beneficial enhancements that are not urgent. and removed pending-triage [Issue] Ticket is pending to be prioritised labels Feb 25, 2025
@tdejager
Copy link

tdejager commented Mar 24, 2025

A workaround I'm using is, when using tailwind is, in my case I only need to reset the margin:

        [BlockTypes.LIST_ITEM]: (node: StoryblokRichTextNode<ReactElement>) => {
            const uniqueKey = `li-${elementCounter++}`;
            return (
                // We need this because <Paragraph> adds margin and
                // Storyblok adds a <p> in list items
                <li key={uniqueKey} className={"*:m-0!"}>
                    {node.children}
                </li>
            );
        }

The *: selector selects all children and allows a style override.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has-workaround [Issue] Temporary solutions available. p2-nice-to-have [Priority] Lower priority, beneficial enhancements that are not urgent.
Projects
None yet
Development

No branches or pull requests

3 participants