feat(VEditor): Create new component
resolves #3550
Description
A WYSIWYG editor component. Will add more formatting options as we go.
Todo:
- [x] code cleanup and refactor
- [x] add proper styles.
- [x] implement proper props
- [x] add h1,h2,h3
- [x] add left, right and center alignment
- [x] add tests
- [x] update docs
Markup:
<template>
<v-container class="pa-md-12">
<v-row>
<v-col cols="12" md="8">
<v-editor
v-model="content"
hint="Please enter rich test content"
/>
<br>
<br>
<v-textarea
v-model="content"
label="HTML Output"
rows="4"
readonly
/>
</v-col>
</v-row>
</v-container>
</template>
<script setup>
import { ref } from 'vue'
const content = ref('This is a <s>plain</s> <b>rich text</b> content with <u>formatting</u>.')
</script>
Screenshot
I have a @tiptap/vue-3 wrapped with VField that I would gladly replace it with VEditor. The only requirement would be to have an option to hide the toolbar and show the "bubble menu" upon selection (like here, although this implementation is a bit annoying. Notion has a similar thing but better - shows it only when a piece of text is selected).
(separate comment so people can upvote separately from the previous feature request)
Another thing that comes to mind (something that people ask for in context of VTextField, but would make more sense with VEditor) is @mention support. Again, TipTap has some "extension", but the UX feels like 4/5. I don't say we should deliver it... could we make it easy for the users to extend the component on their own?
P.S. both of these are ideas for the future development.
@J-Sek There seems to be significant demand for Vuetify WYSIWYG component:
- https://github.com/vuetifyjs/vuetify/issues/3550
- https://github.com/vuetifyjs/vuetify/issues/9359
- https://github.com/vuetifyjs/vuetify/issues/11884
- https://github.com/vuetifyjs/vuetify/issues/2403
Excellent work on the new VEditor component! This is a much-needed addition to the framework.
It looks like the current implementation uses an HTML string as its model. While that works, have you considered adopting a structured JSON format (like Portable Text) for the content instead?
This approach offers some significant advantages for Vuetify developers:
Improved DX
Instead of developers being forced to use the v-html directive (which Vue's own documentation warns against) when rendering the content, they could easily map editor content to actual Vue components. This is a much more powerful and "Vue-native" way to render rich text, giving developers full control over the output.
Enhanced Security
By outputting a structured object, VEditor would inherently guide developers away from v-html, mitigating the risk of XSS attacks. This would make applications built with Vuetify safer by default.
Powerful Extensibility
A structured format would allow developers to easily embed other Vuetify components (VCard, VAlert, etc.) directly into the editor's content. Imagine being able to represent a VAlert in the editor with a clean JSON object, rather than a fragile, custom HTML tag that needs parsing.
For example, instead of this:
<div class="v-alert-custom">...</div>
The model would be:
{ _type: 'v-alert', props: { color: 'error', text: 'This is an alert!' } }
Easy Content Reusability
An HTML string is great for a web page, but a structured JSON object is truly portable. Developers could easily repurpose the content for mobile apps, RSS feeds, or other non-browser environments without complex HTML stripping. Using the existing Vue Portable Text renderer makes rendering the content straightforward in Vue apps.
Adopting a spec like Portable Text could provide a solid foundation without reinventing the wheel. You can check out the playground to try it out.
Just a thought for the long-term flexibility and power of the component. The work you've done so far is fantastic, and I'm excited to see it released!
Will it be possible to embed "diagram-as-text", see https://github.com/mermaid-js/mermaid ? Effectively allowing a process to generate text / diagram-as-text.
Maybe it's a no-brainer...I must admin I haven't looked closely enough at VEditor.
Will there be options to save the content in other formats (e.g. markdown, structured JSON) besides HTML?
Thinking some kind of utility like how TipTap has done for prose mirror could be helpful behind the scenes: https://tiptap.dev/docs/editor/api/utilities/static-renderer
Once this is merged, are there any improvements already planned?
I'd love to see support for <a>, <hr>, <sub>, <sup>, <ul>, <ol> tags and task lists.
@davidstackio Portable Text format looks very promising and is definitely a robust approach. However, at the moment we are not considering implementing it primarily because:
- We don't use third-party libraries to build Vuetify components so using libraries like '@portabletext/to-html' is not possible.
- Implementing custom logic for conversion between html and portable text formats is a lot of work and is not a priority at the moment.
Maybe in the future iterations we might implement this. But for now, I would recommend implementing the conversion layer outside the component.
Will it be possible to embed "diagram-as-text", see mermaid-js/mermaid ? Effectively allowing a process to generate text / diagram-as-text.
Maybe it's a no-brainer...I must admin I haven't looked closely enough at VEditor.
This isn't straightforward. mermaid-js uses a markdown-like syntax to build the diagrams and we don't have plans to support markdown at the moment.
Once this is merged, are there any improvements already planned? I'd love to see support for
<a>,<hr>,<sub>,<sup>,<ul>,<ol>tags and task lists.
@jmamakeesic
<sub>, <sup> are already implemented and can be added to the editor by using formats prop
We have immediate plans to implement <ul>, <ol> , <a> and also the ability for users to add their own
Will it be possible to embed "diagram-as-text", see mermaid-js/mermaid ? Effectively allowing a process to generate text / diagram-as-text.
Maybe it's a no-brainer...I must admin I haven't looked closely enough at VEditor.
I don't think these are related at all. That has more to do with markdown itself.
- [x] do not use
primaryfor active state- currently active buttons disappear when
:toolbar-props="{ color: 'primary' }"
- currently active buttons disappear when
- [x] fix:
style="background-color: #333"being injected to the model when used withtheme="dark"- when using
enterand thenbackspacewhile the cursor is at the start position (sometimes happens withdeleteas well)
- when using
- [x] fix:
backspaceneeds to be pushed twice when at the beginning of a line
- [ ] fix: cannot break line using
enterwhen there is any selection - [ ] fix: background color still appears after removing line break
- [ ] fix: (minor) avoid unnecessary
when breaking and restoring lines (white-space: pre-wrapmight help a bit) - [ ] fix: pasting any text in new line gets background-color
- [ ] fix: (minor) left arrow needs to be clicked twice to move up from an empty line
- [ ] fix: (minor) backspace removes 2 empty lines
- Available to insert table
- Available to insert image
- Available to insert audio / video
- Available to upload drag or drop file
We're watching this one with a lot of interest, as it will finally allow us to deprecate Quill. Any updates? Thank you.
Just also would like to express interest in this.