-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
How do you render html without the Editor ? #657
Comments
What's the issue with using serialized HTML from |
@BrianHung You mean with |
@BrianHung I think I got your answer wrong.
There is none. If you store it in a DB and retrieve it later, how would you render it ? |
I think I understand your question better now: you want to render the HTML into normal Vue Components. I would look at Editor.js and try to isolate the parts which renders the components, like |
@BrianHung Yes, but I don't understand why I am the first to ask this, I must have missed something. How do you (tiptap's users) consume the serialized HTML usually ? Editing is one part of the story, you have to consume the content next, don't you ? |
I just use the editor to render the HTML and use read-only. |
Ok got it. I don't know why it did not seem intuitive to me to use the editor to only display content at first glance. I am working on a CMS app where most of users are in a "consume only" mode. At first I thought that the serialized HTML was meant to be used with the |
I come here with same goal. to make components both for editing and reading modes. I would appreciate anyone having experience confirming the approach @ThomasKientz is using. Thanks |
That’s what we made the read-only mode for, so it’s fine. 👍️ |
Hi @ThomasKientz, would you care to share any experience you had with this suggested approach (ie. using the read-only mode)? I tried to build a minimal project with TipTap using the read-only mode to see what would be the final bundle size and wasn't surprised to see a 316Kb(parsed), gzipped: 96Kb, since it packs everything required for the actual editor with all its editing functionality. Thanks so much in advance, guys! |
There are three ways:
|
Thanks for your input @philippkuehn! It seems like the guys at Storyblok created a HTML render for ProseMirror JSON data: Storyblok.richTextResolver.render(blok.richtext) What they call And this is the parser logic: https://github.com/storyblok/storyblok-js-client/blob/933dc19369fd6b62db42595781a15b957b663e6a/source/richTextResolver.js#L20 This might be useful for anyone looking into writing their own lightweight renderer. |
Hey, in v2 there is also a |
That's great news, thanks for sharing @philippkuehn. |
I ending up exporting html with I am doing this, because I am using custom Vue components as nodes. So I can't render the html as is as I need a way to parse and render the customs nodes (eg A lightweight reader components (to replace |
I have similiar issue, i have my custom nodes, for example - spoiler node, which show and hide the content by the button click, this just update attribute "show", and when i toogle editor to read-only mode then click by the button doesn't work, i don't know what i really need to do to fix this problem (#1415) . Maybe do you know? |
I tried to use it, it says: ReferenceError: window is not defined
at doc (C:\server\node_modules\prosemirror-model\src\to_dom.js:194:30) I also tried to add it to jsdom window, still no result. @Winexcel @ThomasKientz @philippkuehn |
If you use custom extensions that use events, this won't work for you. For each such extension you need to write a parser that will implement logic on top of html. Just see this extension https://github.com/Winexcel/tiptap-spoiler |
I dont know if any of you notice, with the help of VS Code IDE I was able to find import { generateHTML } from "@tiptap/vue-3";
const jsonData = {}; // the generated json from the editor
const html = generate(jsonData); // then I just render this on the html the reason Im json json to the database is becuase of the xss issue. |
There is a fourth option and it's usually recommended by some rich text editors that I've used/evaluated. Why proposed solutions might not work for you?
Solution: write your own renderer. I didn't say it's the easiest solution. 🤠 // super basic example in JSX
function renderElement(el) {
const children = el.content.map(child => renderElement(child));
// few handled cases to give a taste
if (el.type === 'text') return el.text;
if (el.type === 'paragraph') return <p>{children}</p>;
return null;
}
function Document(props) {
return (
<div>
{/* props.document === {type: "doc", content: [...]} */}
{props.document.content.map(child => renderElement(child))}
</div>
);
} Few points to make:
|
Hi. So far there is no way to do it? Thanks. |
we did that on Dante3, (tiptap based editor) it let you render custom components (react) |
I think one of the reasons a built in renderer has not been built by the team behind tiptap is that a renderer that would cover all edge cases in the limit will be the editor component. Therefore I guess if we need any type of lighter version of the rendered we will have to implement it ourselves depending on the case at hand |
Would look into https://github.com/nytimes/react-prosemirror |
here is a renderer implemented in ruby https://github.com/chaskiq/chaskiq/blob/main/app/services/dante/renderer.rb This is useful to render HTML from ruby backends. |
you can do const content : "<p>Some text here</p>";
return (
<div dangerouslySetInnerHTML={{ __html: content }} />
) |
Just adding a note that I would also love to use some type of renderer. The less-than-ideal approach I'm taking so far:
The downsides of this approach:
Some ideas I've toyed around with to improve this:
EDIT: It actually seems easier than expected to create the custom renderer, and it gives us more flexibility, so we'll be proceeding with that. |
I found a way to render HTML from the TipTap editor without worrying about style collisions. I used an const SimpleHtmlRenderer = ({ html }: { html: string }) => {
const iframeRef = useRef<HTMLIFrameElement>(null);
useEffect(() => {
const iframe = iframeRef.current;
if (iframe) {
iframe.onload = () => {
iframe.style.height =
iframe.contentWindow?.document.body.scrollHeight + 'px';
};
}
}, [html]);
return (
<iframe
ref={iframeRef}
srcDoc={html}
style={{ border: 'none', width: '100%' }}
sandbox="allow-same-origin"
/>
);
}; This way, I don't have to worry about any style collisions. The iframe's height adjusts automatically based on its content, so it fits nicely. Hope this helps! |
This will be the official supported solution: #5528 It is usable now by installing the @tiptap/static-renderer package commented by the pkg-pr-new bot |
Hi,
I don't find a clear way of how to consume the templates produced with the editor.
Once your users have created some nice templates with the editor (eg in a "Edit" page), how do you render them if you just want to display them without any editing functionalities (eg in a "Blog" page in a read only mode) ?
To avoid spin up again a full editor in read only mode (
:editable="false"
), I am trying to naively create a minimalist renderer component that takes in parameters the compiled template string (produced fromgetHTML()
) and render it with all my custom nodes/components. But compiling templates downloaded from a backend on the fly its not straightforward.How do you process for this kink of scenery ?
Thanks !
The text was updated successfully, but these errors were encountered: