Termdom – Build Terminal Apps with HTML, CSS and the DOM

philips1 pts0 comments

TermDOM | Build Terminal UIs with HTML, CSS and DOM<br>termdom<br>Build Terminal UIs with HTML, CSS and DOM.<br>npm install @b9g/termdom<br>a real DOM, a real cascade, a real layout engine — rendered to your terminal<br>TermDOM is a JavaScript library that displays HTML and CSS in the terminal. It<br>draws actual DOM nodes to terminal output and redraws the screen when they<br>mutate, so TUIs and interactive CLIs can be written with vanilla JavaScript or<br>any frontend web framework.<br>import {TermDOM} from "@b9g/termdom";

const term = new TermDOM();<br>term.attach();

// The document is a real DOM document.<br>const {document} = term;<br>document.body.innerHTML = `

.card { border: 1px solid #5fafff; padding: 0 1ch; width: 36ch; }<br>.title { color: #5fafff; font-weight: bold; }<br>.done { color: green; }<br>.rest { color: #444; }<br>.pct { color: #888; }

Installing

`;

// TermDOM observes mutations and re-renders automatically.<br>let n = 0;<br>setInterval(() => {<br>n = (n + 1) % 101;<br>const cells = Math.round(n / 4);<br>document.getElementById("done").textContent = "█".repeat(cells);<br>document.getElementById("rest").textContent = "░".repeat(25 - cells);<br>document.getElementById("pct").textContent = String(n).padStart(3) + "%";<br>}, 50);<br>One cell is 1ch wide and 1px tall. Every box lands on whole cells.<br>Write a web page. Get a TUI. #<br>Every glyph below is a DOM element. The spinner is a whose textContent mutates; painting is automatic, like the browser.<br>const spinner = document.createElement("span");<br>spinner.className = "spin"; // .spin { color: green }<br>section.appendChild(spinner);<br>setInterval(() => {<br>spinner.textContent = frames[n++ % frames.length];<br>}, 30); // no render call -- mutations paint<br>Interactivity is just DOM events. #<br>A NERDTree-style file browser in ~200 lines of vanilla DOM: querySelectorAll for the rows, classList for the selection, keydown for the keys, and scrollIntoView() to move the camera.<br>document.addEventListener("keydown", (ev) => {<br>if (ev.key === "j") select(selected + 1);<br>if (ev.key === "Enter") expand(rows()[selected]);<br>});<br>rows()[selected].scrollIntoView();<br>Real text input. Real caret. Real IME. #<br>elements with focus traversal and :focus styling — and the caret is the real terminal cursor, so CJK input methods compose in the field, measured in cells.<br>div class="field"><br>div class="label">Namediv>input id="name"><br>div>

field.addEventListener("input", updatePreview);<br>Features #<br>Stylesheets CSS from elements and style attributes cascades and inherits like it does in the browser, and is translated to ANSI escapes for color and text decoration.<br>Layout The CSS box model, flexbox, and table layout. Sizes resolve to whole cells.<br>Text CJK, emoji, and combining characters take their correct widths. Hebrew and Arabic render in visual order with contextual shaping, and the caret moves by grapheme.<br>Scrolling Documents taller than the terminal scroll with window.scrollTo() and element.scrollIntoView().<br>Events Events for keys, mouse, focus, and paste fire on elements, the document, and the window, pulled from STDIN.<br>DOM utilities document.querySelector(), MutationObserver, ResizeObserver, and Element.getBoundingClientRect() are hooked up to the layout engine and viewport, following browser standards.<br>Forms , , , checkboxes, and radios come with default behavior and terminal-native looks, and can be restyled with ordinary CSS. Tab navigation and :focus styles are supported.<br>Web Components customElements.define(), attachShadow(), , :host, and scoped styles behave like the browser's. The built-in form controls are themselves shadow trees.<br>Selection Drag to select, styled with ::selection.<br>Fullscreen Element.requestFullscreen() renders an element to the alternate screen. Exiting restores the shell and its scrollback.<br>Compatibility #<br>The compatibility matrix is generated by a probe suite: each DOM API, selector, and CSS property is applied to a real document and rendered, and the table records whether the output changed.<br>Get started #<br>npm install @b9g/termdomGuides → · Examples on GitHub →

MIT Licensed · A bikeshaving project

document termdom terminal real color cells

Related Articles