Building LiteBuilder - A Lightweight Live HTML Editor in Vue 3


I recently built LiteBuilder - a simple yet powerful live code editor using Vue 3 and Tailwind CSS. It supports syntax highlighting, tag suggestions, live preview, file import/export, and even Tailwind-based styling.

All of it runs directly in the browser, with zero heavy dependencies - everything is custom-built, including the editor core using a plain <textarea>.


Key Features

  • Syntax highlighting inside a native <textarea>
  • Smart tag autocompletion
  • Save & import .txt files to continue editing later
  • Export your HTML code directly
  • Live preview with Tailwind styling
  • Auto formatting

How it works

Syntax Highlighting via Overlay

LiteBuilder uses a clever trick - a hidden <pre> element mirrors the <textarea> content and applies syntax highlighting through custom parsing.

Here’s the basic setup:

<template>
  <div class="relative font-mono">
    <pre class="highlight-layer" v-html="highlightedCode"></pre>
    <textarea v-model="rawCode" @input="onInput" class="editor-layer"></textarea>
  </div>
</template>

Inside highlightedCode, the text is parsed and injected as HTML:

function highlightHTML(raw: string): string {
  return raw
    .replace(/(&lt;\/?[a-z-]+&gt;?)/gi, '<span class="text-red-500">$1</span>')
    .replace(/(&quot;.*?&quot;)/g, '<span class="text-green-500">$1</span>')
}

This function is used to keep a synchronized, styled preview of what you’re typing.

Tag Suggestions While Typing

As the user types inside the editor, LiteBuilder detects open brackets (<) and displays a suggestion list:

function getTagSuggestions(currentText: string): string[] {
  const tags = ['div', 'span', 'button', 'input', 'p', 'a', 'img']
  return tags.filter(tag => tag.startsWith(currentText))
}

Suggestions are rendered in an absolutely positioned list over the editor.

Saving and Loading from File

Saving is handled using Blob and a simple download trigger:

function downloadFile(content: string) {
  const blob = new Blob([content], { type: 'text/plain' })
  const a = document.createElement('a')
  a.href = URL.createObjectURL(blob)
  a.download = 'litebuilder.txt'
  a.click()
}

And file input is used for importing:

<input type="file" accept=".txt" @change="onFileUpload" />

Live Preview + Tailwind Integration

The live preview is rendered in an <iframe> sandbox. Content is injected like so:

iframe.contentDocument!.body.innerHTML = `
  <div class="prose">${rawCode.value}</div>
`

Tailwind is preloaded into the iframe context - which allows users to apply Tailwind classes live and immediately see the result.

Code Formatting

For formatting, the editor uses a simple parser that ensures consistent indentation and spacing. You can trigger it with a button click:

function formatCode(raw: string): string {
  return html_beautify(raw, { indent_size: 2 })
}

Why I built this?

I wanted full control over the editing experience - without relying on big libraries like CodeMirror or Monaco. I also wanted to focus on:

  • minimal UI,

  • fast feedback loop (live preview),

  • and full offline usability.

This is especially useful for:

  • testing Tailwind layouts,

  • prototyping static HTML,

  • or teaching the basics of HTML structure and semantics.

Final thoughts

LiteBuilder was a fun project that pushed me to work closer with raw DOM APIs and Vue reactivity without relying on external editors. It’s a great reminder that with the right mindset, you can build tools yourself - even the ones you’re used to importing as packages.

Bartłomiej Nowak

Bartłomiej Nowak

Programmer

Programmer focused on performance, simplicity, and good architecture. I enjoy working with modern JavaScript, TypeScript, and backend logic — building tools that scale and make sense.

Recent Posts