ueberdosis / tiptap

The headless rich text editor framework for web artisans.
https://tiptap.dev
MIT License
27.51k stars 2.29k forks source link

Request: more control over child divs created by node views #1527

Closed thatsjonsense closed 2 years ago

thatsjonsense commented 3 years ago

The problem I am facing When working with Node Views in React, Tiptap creates two wrapping divs around both the node view itself and the content. Visually:

<div class="react-renderer">
  <div data-node-view-wrapper>
    <my node view HTML>
      <div data-node-view-content>
        <div>
           <the node view content>

This is fine for many blocks but can lead to non-semantic HTML and messed up rendering. In my case, I created a TableRow node view and so I end up with DIVs between the TR and TD tags.

The solution I would like Ideally, my content could be rendered without any intermediate divs. I don't know enough about Prosemirror to see why these are needed in the first place. Alternatively, I wish there was a single wrapping div and I could control the tag used for it.

Alternatives I have considered For now, I'm getting around this by applying the display: contents CSS property to the intermediate divs to prevent them from actually rendering. This is messy but seems to work alright. It makes me wonder if the divs are actually providing any value, since they aren't being displayed.

hanspagel commented 3 years ago

Does that help?

The NodeViewWrapper and NodeViewContent components render a <div> HTML tag (<span> for inline nodes), but you can change that. For example <NodeViewContent as="p"> should render a paragraph. One limitation though: That tag must not change during runtime.

https://www.tiptap.dev/guide/node-views/react#adding-a-content-editable

thatsjonsense commented 3 years ago

Hi @hanspagel , thanks for the suggestion but no it doesn't. When you set as="p" it only changes how the outer node renders. I believe it still renders a div inside of that, so instead of <div><div> you get <p><div>

tmm commented 3 years ago

This is an issue for me as well.

I'm trying to add an editable caption to an image and need to set up onKeyDown to prevent Enter from splitting the node (this also happens in the demo in the docs):

<NodeViewWrapper as="figure" className="react-component-with-content">
  <img alt={attrs.alt} src={attrs.src} />
  <NodeViewContent
    as="figcaption"
    role="textbox"
    tabIndex={-1}
    onKeyDown={onKeyDown}
  />
</NodeViewWrapper>

Unfortunately, this doesn't get passed down to the div inside figcaption (NodeViewContent).

Would be great to either remove the inner div inside node view content or be able to pass props down to the inner div.

philippkuehn commented 3 years ago

Unfortunately we can’t remove any of these divs. It’s because node views (dom and contentDOM) have to be synchronous. React can only render asynchronous. In Vue.js we don’t have to render these wrapper nodes.

jorchg commented 3 years ago

For me the problem is that I am trying to use a component from an external library, but this component accepts only String children, so when I try to create a new node and pass down the content to the component, always get (as normal) the error Warning: Failed prop type: Invalid prop 'children' of type 'object' supplied to 'CodeSnippet', expected 'string'.

I am passing ReactNodeViewRenderer this component:

const CustomCode = (props) => {
  return (
    <NodeViewWrapper as="span" className="carbon-code">
      <CodeSnippet type="inline">
        <NodeViewContent as="span" />
      </CodeSnippet>
    </NodeViewWrapper>
  );
}

Is there anything I can do to just pass a textNode down to my CodeSnippet component? Thank you :)

philippkuehn commented 2 years ago

Fixed by https://github.com/ueberdosis/tiptap/pull/2213

anton-liubushkin commented 2 years ago

@philippkuehn I'm sorry, but I don't understand how #2213 fixes the problem with the extra inner div of NodeViewContent?

seleckis commented 8 months ago

This issue is still actual, cannot add extra table cell to table row without breaking the table structure with extra div. Please reopen