A Notion-like forn using Vue 3, Vite and TailwindCSS

  • By Vanessa Otto
  • Last update: Dec 18, 2022
  • Comments: 17

Vue Contenteditable Form

Prototype: A Notion-like Form written in Vue 3, Vite, and TailwindCSS


Live Demo


Use the package manager npm to install Vue Contenteditable Form.

npm install

Alternatively, use the package manager yarn to install Vue Contenteditable Form.

yarn install


Use the dev command to run Vue Contenteditable Form locally.

npm run dev
# or 
yarn dev

The script tells you on which port the website is available.


The test files are in src, right next to the tested components. Spec files are named as the component with the suffix spec: *.spec.js.

Run the following command to open the Component Test Runner:

npm run test


The main branch of this repository is automatically deployed on Vercel.

To build the project, run

npm run build
# or
yarn build

To serve the project, run

npm run serve
# or
yarn serve

Project Roadmap

This project is currently in a prototype state. You can check out the project board on GitHub.

Currently implemented and planned features are:

  • Add end edit contenteditable blocks
  • Store to LocalStorage
  • Add Button for new blocks
  • Make block tags changeable with rich text buttons
  • Add images
  • Resize images


Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests and documentation as appropriate.






  • 1

    fix: #5

    fix: #5 delete block with 'backspace' and the caret is on the first position.

    concat previous block and deleted block

    updateBlock does not rerender the new content, so I introduced a .version for each block that is the :key for vue rendering. and on changing that version causes a rerendering => we see the new content in the browser.

    but unfortunately than there is an error in the vue-contenteditable npm package. rerender block

    That delete-feature is working but that error in dev-tools isn't good. Do you have an idea?

  • 2

    Use / to add a title


    As a user, I want to be able to turn a field into a title.


    When starting a block with / a popover opens. This popover shows the option "title". When the user selects title, the HTML block should be converted from a <p> to an <h2>. The design is open for imagination, something less big than the <h1> of the page title.


    For now, this only needs to work when the block itself is still empty. Tally.so creates a new block below when using the / shorthand in a block with content.

    Next Steps

    • "Turn into" action next to delete-action
    • Subtitle with <h3>
  • 3

    Copy + Paste on a block should duplicate it


    As a user, I want to duplicate a block by clicking Cmd C + Cmd V (macos Example. Should work for all OSs)

    Acceptance Criteria

    • When copy/pasting a block, not matter if text, image or else, should be added right below the current block.
    • Exception: Page title
  • 4

    copy-paste #16

    copy-paste works, but the "normal text-copy-paste" does not :-(

    to copy a block no text should be selected.

    getting data from the clipboard needs permissions from the browser - so the first time a dialog appears.

    • how do other apps deal with the clipboard permission ???
  • 5

    feat: add image block

    fix svg-attributes on svg icons add image block on + with file picker

    sorry, I don't know what second point on acceptance-criteria means (It displays the options "Image")

    currently there is no special image centering of size limitation. do we need one ?

    saving works without any changes - well done: JSON.stringify :-)

  • 6

    feat: focusses blocks before or after when using key up and down (clo…

    …ses #13)

    This is not a perfect solution yet, but it works. Vue prints the warning runtime-core.esm-bundler.js:38 [Vue warn]: Invalid event arguments: event validation failed for event "update:modelValue". for empty blocks. I think it's unrelated to the cursor up/down (happens when clicking enter as well), so I want to fix that in another PR

  • 7

    blocks should be deletable


    I see two ways of deleting a block:

    • press Backspace on an empty the block
    • special button (left of the drag-gripper) looking like a waste bin

    tally.so does deleting the current block on pressing Backspace if the cursor in at the start of the block. Then the block is deleted and - if there was any text right of the cursor - the deleted text will be contacted to the block before the current block.

    may be we start with Backspace on an empty block.

  • 8

    cursor up/down not working on images

    I see two solutions:

    • ignore the image-block and jump to the next none-image-block
    • make it possible to have the image-block been the "current" block. (usefull to delete the image-block with ). the next cursor up/down then will than leave this image-block and jump to the next block
  • 9

    Add Images via "+" button


    As a user, I want to be able to add images to my form by clicking on a "plus button" which opens my file browser.

    Acceptance Critieras

    • [x] There's a button with "+" next to all blocks
    • [ ] It displays the options "Image"
    • [x] It opens the file browser
    • [x] It allows to upload png and jpgs as a gif
    • [x] Image is added in the next block
    • [x] Images can be drag/dropped after
    • [ ] The Image is centered within it's block (it might be worth it to wrap the image within a


    Next Steps

    • When clicking plus there will be a dropdown first, asking the users for what to add: Image, Title, Paragraph, List, Video etc.
  • 10

    cursor down on empty text block should jump to next block if there is any

    Bug & History

    Focusing next block doesn't work when current block is an empty string. This behavior was implemented to prevent using cursor down-down-down to create a lot of useless empty blocks.

    Expected Behavior

    When a text block is empty but there is a next block, it doesn't focus this next block.

    Actual Behavior

    When a text block is empty but there is a next block, it doesn't focus this next block.


  • 11

    feature: adds delete action with bin icon next to text block


    This PR adds the bin icon next to an HTML block to delete it from the blocks. I couldn't find out how to add you as a reviewer, I try to find out if I can add you as a collaborator to the project or something like that

  • 12

    WIP: feat: #31 improve paste

    pasting a copied block into an empty block will not create a new block, but exchanges that empty block.

    will fix #31

    unfortunately sometimes there are errors in the dev-console on vue-contenteditable

  • 13

    Proposal: Pasting in same line when empty

    Hi @ReneCode,

    I wondered if it UX is improved by pasting a block (not plain text) in the focused block when it is empty instead of adding a new block. What do you think?


  • 14

    add testing

    To ensure current feature will not be acidentlly broken by new featues, I see the need of some automated testing.

    These tests have to be on a level of "user-input", so they are not unit-tests but more e2e tests.

    • [x] choose testing tool. cypress ?
    • [ ] write a simple test
    • [ ] integrate testing into CI
  • 15

    Images should be resizeable


    As a user, I want to be able to resize images because full width might be too large.

    Acceptance Criteria

    • When clicking on a image block, it gets focused
    • On the left and on the right, the cursor turns into the type "col-resize" (see MDN Docs Cursor for more details)
    • When mousedown the cursor, the image should shrink and grow until mouseup
  • 16

    Bold + Italic actions on text selection


    As a user, I want to be able to make select text and turn it into bold, italic, stike-through and code-formatted text.


    As of now, there is a toolbar displayed above text selections. It shows buttons to turn the text bold and/or italic. When activating a button, the code simply surrounds the text selection with a <strong> or <em> HTML tag.

    The problems with that are:

    • no possibility to un-bold or un-italic a text selection
    • several clicks on "bold" or "italic" just add more and more HTML tags around the selection
    • trying the action on a partly-surrounded text selection, doesn't work properly and leads to invalid HTML. Example: Think of the text: "I am a text with a bold text yippieh". The HTML is: I am a text <strong>with a bold text</strong> yippieh. Now think of selection "bold text yippieh"to turn "yippieh" bold as well. This won't work, as the HTML would be I am a text <strong>with a <strong>bold text</strong> yippieh</strong>.

    Possible Solution


  • 17

    Resetting doesn't update title

    Bug Report

    Resetting doesn't update title

    Expected Behavior

    When clicking on "reset", the page title is reset.

    Actual Behavior

    When clicking on "reset", the page title is not reset.

    Steps to reproduce

    1. Update Page Title
    2. Click on Reset
    3. Page Title stays unchanged