Building a Basic Text Editor

Vue.js + some basic javascript, html and css. live here: https://editor.alhinds.com/

A simple, but largely finished product.

If you’ve ever used GitHub, you’re likely to have used its text editor. Maybe you cooked up a simple gist, or perhaps you made a simple change to an existing commit — or maybe that’s how you write all your code.

What’s interesting about the editor, and for the matter editors like CodePen, Ideone, and similar is that they have to resolve how they’re going to deal with things like syntax highlighting, various forms of markup, selections, spacing, all sorts of issues, because the basic `<textarea>` html tag is very limited.

See for yourself. Click on most sites which allow richer text formatting or syntax highlighting and notice how you’re most often not actually entering your text into a textbox — or if you are the textbox is not where it appears to be.

Here’s GitHub’s for example.

In the above, the <textarea/> which has the style attribute display: none, is manually overriden to show how it’s sitting above the lower <div/> section you believe you’re editing.

To allow us to take full advantage of CSS and HTML, GitHub has created a secondary render <div/> which we *think* we’re interacting with which includes all of our rich elements, our nice font, and highlighting, with an underlying <textarea/> that we’re actually interacting with.

There are various levels of complexity to do this, but at its heart it’s a pretty simple concept to try and implement, so on I went.

How I did it

I didn’t want to go too deep into what multiple libraries have already attempted but I did have an idea as to how implement a ‘mirror’ to create the same as the above effect.

I’m using marked for markdown parsing, and highlightjs for all other syntax highlighting. This eased my focus on simply creating the mirror rather than worrying about other parsing challenges.

Similar to how I’ve explained above I used a <textarea/> to hold the input text, although having played around with it, it would’ve also worked with a vanilla contenteditable <div/>. This sits perfectly aligned with the render <div/>, which the user believes they are editing their text in.

The result is pretty good, there’s no perceptible difference in input lag due to the dual-rendering, although I’ve not tried with huge documents (not really the point of the project).

The key challenge was getting the spacing, alignment, and selections to lineup as desired. This wasn’t entirely trivial as it required font syncing, appreciation and proper rendering of whitespace (HTML strips by default).

ALSO disregard tab-spacing and font-size, they’re yet to be dynamic despite being selectable options.

HTML, Markdown & JS execution

Happy with the initial structure I went on to add a few more features including JS code execution (using eval :() and an <iframe> to allow proper inline html rendering. You can play around with those by simply changing the file-type. Yay.

--

--

Short project bios, devtips for use in my portfolio.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Al Hinds

Al Hinds

Write about all sorts of stuff. Dev. Sport. Life.