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
.txtfiles 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(/(<\/?[a-z-]+>?)/gi, '<span class="text-red-500">$1</span>')
.replace(/(".*?")/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
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.