HarshPatel

Ahmedabad, Gujarat
Back to Projects
Next.jsReactTailwind CSS

Raw data to Webpage Convertor

A zero-backend browser tool that converts raw markdown or plain text into a fully styled, responsive, self-contained HTML documentation page — complete with auto-generated table of contents, Prism.js syntax highlighting, dark/light theme toggle, mobile sidebar navigation, split-screen editing, search & replace, PDF export, and markdown export. No server, no dependencies, one-click download.

May 202623 views📷 4 photos
Raw data to Webpage Convertor 1
1 / 4

Introduction

Writing documentation is one thing. Presenting it well is another. Most developers write their notes, guides, and tutorials in plain markdown, then either leave them as raw .md files or drop them into a third-party platform they don't control. I built HTML Documentation Generator to bridge that gap — a browser-based tool that takes your raw markdown or plain text and converts it into a complete, self-contained, beautifully styled HTML documentation page in real time, with no backend, no server, and no external services.

Paste your content, see the output live, and download a single .html file that works completely offline — including syntax highlighting, dark/light theme toggle, mobile navigation, and a generated table of contents.

What it does

The tool is a real-time markdown-to-HTML converter with a full documentation page template baked in. Everything the output page needs — CSS, JavaScript, theme logic, mobile sidebar, copy-to-clipboard — is inlined into a single .html file that you can open in any browser without an internet connection (except for loading Prism.js from CDN on first use).

  • Real-time conversion — the HTML output regenerates 300ms after every keystroke in the input panel, debounced to avoid unnecessary reprocessing on fast typing.
  • Split-screen editing mode — toggle a side-by-side layout with the markdown input on the left and the generated HTML source (or live preview) on the right, keeping both panels visible simultaneously.
  • Live iframe preview — toggle from HTML source view to a live rendered preview via a sandboxed <iframe> loaded with data:text/html;charset=utf-8,.... The preview is fully interactive — theme toggle, copy buttons, and mobile sidebar all work inside the preview frame.
  • Fullscreen preview mode — expand the output panel to fill the entire viewport for distraction-free review of the generated page.
  • Auto-generated table of contents — every h1, h2, and h3 heading in the input is extracted and added to the sidebar TOC with anchor links. The sidebar collapses on mobile with a hamburger menu overlay.
  • Prism.js syntax highlighting — fenced code blocks (```javascript, ```python, etc.) are converted into Prism-highlighted <pre><code> blocks with a per-block Copy button. The language label is displayed in the code block header.
  • Dark/light theme toggle — the generated page has a fully working theme system using data-theme on the body element, CSS variables for every color token, and localStorage persistence so the user's preference is remembered across sessions.
  • Search & replace — a modal dialog (triggered by the toolbar button or Ctrl+F) lets you search for any string in the markdown input and replace all instances at once via a global regex.
  • Multiple export formats — download as .html (Ctrl+S), export the raw markdown as .md, open the print dialog for PDF export, or download a documentation package bundle.
  • Keyboard shortcutsCtrl+S downloads the HTML, Ctrl+F opens search, Ctrl+Enter triggers replace all, Escape closes any open dialog or fullscreen mode.

Tech stack

  • Next.js 14 (App Router) — framework and routing. Like the other tools in this portfolio, the entire application is a single 'use client' component — Next.js is used for its build pipeline, TypeScript support, and Vercel deployment, not for SSR.
  • React 18useState, useEffect, useCallback, useRef. No external state management. The entire conversion pipeline is driven by a single useEffect watching rawContent.
  • shadcn/ui — component library for the editor UI: Card, Button, Textarea, Input, Badge, Dialog, Separator. The generated HTML output uses none of these — it's a completely independent vanilla CSS page.
  • Tailwind CSS — utility styling for the editor application shell. The generated HTML page uses custom CSS variables only — no Tailwind in the output.
  • next-themes — theme provider for the editor UI itself (separate from the theme system inside the generated HTML output).
  • Prism.js (CDN) — loaded in the generated HTML output via cdnjs.cloudflare.com for syntax highlighting. The autoloader plugin handles language detection automatically, so no individual language bundles need to be specified.
  • Lucide React — icon set for the toolbar buttons.
  • Blob + URL.createObjectURL — all downloads (HTML, markdown) are generated client-side with no server round-trip.
  • Vercel — deployment and hosting.

The conversion pipeline

The convertToHTML function is a line-by-line markdown parser that walks the input string and builds the HTML output document incrementally. It's deliberately simple — not a full CommonMark parser — because the target use case is technical documentation with a known, consistent format: headings, paragraphs, fenced code blocks, and inline bold.

for (let i = 0; i < lines.length; i++) {
  const line = lines[i].trim()

  if (line.startsWith('# '))        → h1 + TOC entry
  if (line.startsWith('## '))       → h2 + TOC entry
  if (line.startsWith('### '))      → h3 + TOC entry (indented)
  if (line.startsWith('```'))       → collect lines until closing ```, emit code block
  if (line.startsWith('**') && line.endsWith('**')) → standalone bold paragraph
  if (line.length > 0)              → paragraph with inline **bold** processing
  else                              → blank line (whitespace)
}

The code block parser is stateful — when it hits an opening fence (```language), it increments i and accumulates lines until it hits a closing fence, then emits the full .code-container block with a language label, a per-block Copy button, and the content HTML-escaped (<&lt;, >&gt;) to prevent injection. The copy button uses data-code="encodeURIComponent(content)" to safely pass the code content as an attribute.

The generated HTML page

The output is a completely self-contained HTML document — no external stylesheets, no framework dependencies. Everything needed to render the page is inlined:

  • CSS variable theme system:root defines all color tokens for light mode; [data-theme="dark"] overrides them for dark mode. Every element uses these variables, so the entire page re-themes instantly when data-theme is toggled on the body.
  • Responsive layout — fixed sidebar (280px) on desktop, slide-in drawer with hamburger menu and overlay on mobile. The sidebar hides automatically when a TOC link is clicked on mobile.
  • Fluid typography — headings use clamp() for responsive font sizes: h1 scales from 1.8rem to 2.5rem, h2 from 1.4rem to 2rem, h3 from 1.2rem to 1.5rem.
  • Scrollable code blocks — code blocks use overflow-x: auto with custom scrollbar styling (::-webkit-scrollbar) in both light and dark themes. The scrollbar thumb uses the accent color for visual consistency.
  • localStorage theme persistence — the theme toggle reads from localStorage on load and writes back on every toggle, so the user's preference persists across page reloads.
  • Prism.js token overrides — both [data-theme="dark"] and [data-theme="light"] token color overrides are inlined in the CSS, matching GitHub's dark and light syntax highlighting palettes respectively. After every theme toggle, Prism.highlightAll() is called with a 100ms delay to re-highlight all code blocks under the new color scheme.
  • Clipboard API with fallback — the copy button uses navigator.clipboard.writeText() with a document.execCommand('copy') fallback for older browsers that don't support the modern Clipboard API.

Export system

All four export formats are generated entirely in the browser:

// HTML download (Ctrl+S)
new Blob([generatedHTML], { type: 'text/html' })
→ downloaded as documentation.html

// Markdown export
new Blob([rawContent], { type: 'text/markdown' })
→ downloaded as documentation.md

// PDF export
window.open('', '_blank')
→ write generatedHTML to new window
→ call printWindow.print() after 250ms delay
→ browser print dialog (Save as PDF)

// Package download
Blob with metadata comment header + generatedHTML
→ downloaded as documentation-package.html

The PDF export uses the browser's native print dialog rather than a library like jsPDF or Puppeteer — which means it preserves all the CSS styling, syntax highlighting, and layout exactly as the user sees it in the preview, with no server-side rendering required. The 250ms delay before calling print() allows the new window's DOM to fully render before the print dialog opens.

Search and replace

The search and replace system uses a Dialog component from shadcn/ui, triggered by the toolbar button or Ctrl+F. On Replace All, it constructs a global regex from the search term and runs rawContent.replace(new RegExp(searchTerm, 'g'), replaceTerm), updating the state — which in turn triggers the useEffect to regenerate the HTML output with the new content. The keyboard shortcut system is managed by a global keydown listener attached in a useEffect with proper cleanup.

Iframe preview sandboxing

The live preview is rendered inside a sandboxed <iframe> using the data: URI scheme:

<iframe
  src={`data:text/html;charset=utf-8,${encodeURIComponent(generatedHTML)}`}
  sandbox="allow-scripts allow-same-origin allow-popups"
  title="HTML Preview"
/>

The sandbox attribute allows scripts (needed for theme toggle and copy buttons to work inside the preview) and same-origin (needed for localStorage in the preview frame), while blocking form submissions, top-level navigation, and other potentially unsafe behaviors. encodeURIComponent handles all special characters in the generated HTML safely as a data URI.

Responsive editor layout

The editor itself is fully responsive. The toolbar uses flex-wrap with abbreviated button labels on mobile (hidden sm:inline for full labels, sm:hidden for short labels). Split-screen mode activates a lg:grid-cols-2 layout — on smaller screens, the panels stack vertically. Fullscreen preview mode sets the output card to col-span-full and hides the input panel entirely. All panel heights are responsive: 300px on mobile, 500px on desktop, scaling up in split-screen and fullscreen modes.

What I'd improve

  • Full CommonMark support — the current parser handles the most common cases but doesn't support tables, blockquotes, ordered/unordered lists, horizontal rules, or nested inline formatting. Integrating a proper parser like marked or remark would make it production-ready for arbitrary markdown.
  • Real ZIP export with JSZip — the current "package" export bundles everything into a single HTML file with metadata comments. A proper ZIP containing index.html, README.md, and a package.json would be more useful for developers who want a structured deliverable.
  • Custom theme builder — letting users change the accent color, font family, and sidebar width in the editor and see those changes reflected in both the preview and the exported HTML would make the tool significantly more flexible.
  • Local autosave — the content disappears on page refresh. Persisting the textarea content to localStorage on every change would prevent losing work accidentally.
  • Multiple document tabs — for users writing multi-page documentation, being able to maintain multiple documents simultaneously in tabs would be a natural workflow improvement.
  • Custom CSS injection — an advanced panel that lets users paste additional CSS to override the default documentation styles, without editing the generated HTML manually.

Conclusion

HTML Documentation Generator is a tool I built because I kept running into the same friction: I had solid technical notes in markdown, but no clean way to share them as standalone, readable documents without a platform dependency. Building the converter from scratch taught me a lot about the browser's native capabilities — the File API, the Clipboard API, the print system, iframe sandboxing, and data URIs. The most interesting insight was how much you can accomplish with zero backend if you're willing to work with what the browser already provides.

// Tech Stack

Next.jsReactTailwind CSS