The most-installed XML viewers are 2★ and abandoned. So I hand-wrote one.
DEV Community

The most-installed XML viewers are 2★ and abandoned. So I hand-wrote one.

Open a .xml file in your browser and you usually get one of three things: a wall of unindented text, a viewer that freezes the tab on anything big, or - when the XML is actually broken - a blank page that won't tell you why.

So I went looking for a good XML viewer extension. The most-installed ones on the stores are stuck around 2 stars and haven't been updated since 2023. The reviews rhyme: "doesn't work", "freezes", "just shows plain text". I built Xwift to do the three things those don't.

What it does

  • Tree view - collapsible, syntax-highlighted elements, attributes, text, CDATA, comments and processing instructions. Expand/collapse all.
  • Source view - pretty-print (2 / 4 / tab) or minify, with line numbers and one-click copy.
  • Tells you where it's broken - a tolerant parser that keeps going on malformed input and lists every well-formedness problem with its line:column: mismatched and unclosed tags, duplicate attributes, unbound namespace prefixes, an unescaped &, a stray ]]> … click an error to jump to it.
  • Doesn't choke on big files - parsing runs in a Web Worker, so the tab stays responsive where "load it all into the DOM" viewers stall.

The interesting part (for fellow devs)

The whole thing is hand-written with zero dependencies - no DOMParser, no library. That was the point. The parser is a tolerant single-pass scanner that builds a best-effort tree and collects precise errors, and the formatter re-emits significant whitespace verbatim, so mixed content and xml:space="preserve" survive a round-trip.

Before shipping I ran an adversarial audit over the core, and it surfaced 15 real bugs I would never have caught by eye. A few favorites:

  • Namespace scopes were plain objects, so an unbound prefix literally named toString or __proto__ resolved up the prototype chain and got treated as bound. Fixed with Map-based scopes.
  • The serializer was recursive, so a deeply-nested-but-valid document overflowed the call stack even though the iterative parser handled it fine. Rewrote it as an explicit-stack walk.
  • A [hidden] attribute was silently overridden by a display:flex CSS rule - the empty drop-zone covered the whole viewer. My first E2E missed it because it asserted element content, not visibility.

Then it's verified in real Chrome and real Firefox - the parser produces byte-identical output under V8 and SpiderMonkey.

Respectful by default

  • Zero data collection. Everything runs locally - no network requests with your content, no account, no telemetry. Files you open never leave your browser.
  • Minimal permissions. No host permissions, no <all_urls>, no tab snooping. It reads a page only the moment you ask it to.

Get it

What's the worst XML-viewing moment you've had - the freeze, the blank page, or the "valid" XML that very much wasn't?

Comments

No comments yet. Start the discussion.