HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
developit
htm
JavaScript2018–2026
developit / htm

htm

Hyperscript Tagged Markup: JSX alternative using standard tagged templates, with compiler support.

44Distinct people
58Mentions
1Explicit recommenders
9.1KGitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

Hyperscript Tagged Markup: JSX alternative using standard tagged templates, with compiler support.

GitHub

Where it is used

No documented product use was verified in the last source check.

What people are saying

I use htm (Hyperscript Tagged Markup) instead of JSX and I love it. It's just plain JS and works extremely similar to JSX: https://github.com/developit/htm

timdaub used a recommendation phrase. One indexed comment matches. This is a phrase match, not a verdict.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

No other repository is repeatedly linked in the same discussions.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 6:01:08 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year58 dated mentions

Observed mentions: 2018-11-21 00:58:59 UTC to 2026-08-05 05:42:02 UTC.

0510152018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 8 mentions; 4 submissions, 4 comments20182019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 7 mentions; 0 submissions, 7 comments2020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 15 mentions; 1 submissions, 14 comments2021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 6 mentions; 0 submissions, 6 comments2022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 7 mentions; 1 submissions, 6 comments20222023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 6 mentions; 0 submissions, 6 comments2024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 3 mentions; 0 submissions, 3 comments2025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 4 mentions; 0 submissions, 4 comments2026-01-01 00:00:00 UTC to 2027-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments. Incomplete calendar period.2026*

* An incomplete calendar period is marked with an outlined bar. Its count is not directly comparable with a full period.

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC844
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC707
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC15114
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC606
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC716
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC606
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC303
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC404
2026 (partial)2026-01-01 00:00:00 UTC2027-01-01 00:00:00 UTC202

From the project README

An excerpt from the repository, fetched Nov 13, 2026.

Read the project’s introduction
HTM (Hyperscript Tagged Markup) htm is JSX-like syntax in plain JavaScript - no transpiler necessary. Develop with React/Preact directly in the browser, then compile htm away for production. It uses standard JavaScript Tagged Templates and works in all modern browsers. htm by the numbers: 🐣 < 600 bytes when used directly in the browser ⚛️ < 500 bytes when used with Preact (thanks gzip 🌈) 🥚 < 450 byte htm/mini version 🏅 0 bytes if compiled using babel-plugin-htm Syntax: like JSX but also lit The syntax you write when using HTM is as close as possible to JSX: Spread props: <div ...${props}> instead of <div {...props}> Self-closing tags: <div /> Components: <${Foo}> instead of <Foo> (where Foo is a component reference) Boolean attributes: <div draggable /> Improvements over JSX htm actually takes the JSX-style syntax a couple steps further! Here's some ergonomic features you get for free that aren't present in JSX: No transpiler necessary HTML's optional quotes: <div class=foo> Component end-tags: <${Footer}>footer content<//> Syntax highlighting and language support via the lit-html VSCode extension and vim-jsx-pretty plugin. Multiple root element (fragments): <div /><div /> Support for HTML-style comments: <div><!-- comment --></div> Installation htm is published to npm, and accessible via the unpkg.com CDN: via npm: npm i htm hotlinking from unpkg: (no build tool needed!) import htm from 'https://unpkg.com/htm?module' const html = htm.bind(React.createElement); // just want htm + preact in a single file? there's a highly-optimized version of that: import { html, render } from 'https://unpkg.com/htm/preact/standalone.module.js' Usage If you're using Preact or React, we've included off-the-shelf bindings to make your life easier. They also have the added benefit of sharing a template cache across all modules. import { render } from 'preact'; import { html } from 'htm/preact'; render(html`<a href="/">Hello!</a>`, document.body); Similarly, for React: import ReactDOM from 'react-dom'; import { html } from 'htm/react'; ReactDOM.render(html`<a href="/">Hello!</a>`, document.body); Advanced Usage Since htm is a generic library, we need to tell it what to "compile" our templates to. You can bind htm to any function of the form h(type, props, ...children) (hyperscript). This function can return anything - htm never looks at the return value. Here's an example h() function that returns tree nodes: function h(type, props, ...children) { return { type, props, children }; } To use our custom h() function, we need to create our own html tag function by binding htm to our h() function: import htm from 'htm'; const html = htm.bind(h); Now we have an html() template tag that can be used to produce objects in the format we created above. Here's the whole thing for clarity: import htm from 'htm'; function h(type, props, ...children) { return { type, props, children }; } const html = htm.bind(h); console.log( html`<h1 id=hello>Hello world!</h1>` ); // { // type: 'h1', // props: { id: 'hello' }, // children: ['Hello world!'] // } If the template has multiple element at the root level the output is an array of h results: console.log(html` <h1 id=hello>Hello</h1> <div class=world>World!</div> `); // [ // { // type: 'h1', // props: { id: 'hello' }, // children: ['Hello'] // }, // { // type: 'div', // props: { class: 'world' }, // children: ['world!'] // } // ] Caching The default build of htm caches template strings, which means that it can return the same Javascript object at multiple points in the tree. If you don't want this behaviour, you have three options: Change your h function to copy nodes when needed. Add the code this[0] = 3; at the beginning of your h function, which disables caching of created elements. Use htm/mini, which disables caching by default. Example Curious to see what it all looks like? Here's a working app! It's a single HTML file, and there's no build or tooling. You can edit it with nano. <!DOCTYPE html> <html lang="en"> <title>htm Demo</title> <script type="module"> import { html, Component, render } from 'https://unpkg.com/htm/preact/standalone.module.js'; class App extends Component { addTodo() { const { todos = [] } = this.state; this.setState({ todos: todos.concat(`Item ${todos.length}`) }); } render({ page }, { todos = [] }) { return html` <div class="app"> <${Header} name="ToDo's (${page})" /> <ul> ${todos.map(todo => html` <li key=${todo}>${todo}</li> `)} </ul> <button onClick=${() => this.addTodo()}>Add Todo</button> <${Footer}>footer content here<//> </div> `; } } const Header = ({ name }) => html`<h1>${name} List</h1>` const Footer = props => html`<footer ...${props} />` render(html`<${App} page="All" />`, document.body); </script> </html> ⚡️ See live version ▶ ⚡️ Try this on CodeSandbox ▶ How nifty is that? Notice there's only one import - here we're using the prebuilt Preact integration since it's easier to import and a bit smaller. The same example works fine without the prebuilt version, just using two imports: import { h, Component, render } from 'preact'; import htm from 'htm'; const html = htm.bind(h); render(html`<${App} page="All" />`, document.body); Other Uses Since htm is designed to meet the same need as JSX, you can use it anywhere you'd use JSX. Generate HTML using vhtml: import htm from 'htm'; import vhtml from 'vhtml'; const html = htm.bind(vhtml); console.log( html`<h1 id=hello>Hello world!</h1>` ); // '<h1 id="hello">Hello world!</h1>' Webpack configuration via jsxobj: (details here) (never do this) import htm from 'htm'; import jsxobj from 'jsxobj'; const html = htm.bind(jsxobj); console.log(html` <webpack watch mode=production> <entry path="src/index.js" /> </webpac
Read the full README on GitHub

What Hacker News says

15 sources
React can be added to a page with just a script tag in the same way as Vue: https://reactjs.org/docs/add-react-to-a-website.html Having said that, React is normally used with JSX syntax, which requires a compile step. You _can_ use it with "raw" `React.createElement()` calls, but that's generally unwieldy and almost no one does that. However, there's a very neat library called https://github.com/developit/htm , which is an almost-JSX-compatible syntax that uses JS template literal strings, and requires no compile step.
In Vue.js 3
There's nothing wrong with Vanilla JS and jQuery, but if you need more interactivity, it's possible to use modern libraries like React (with htm [1]) or Vue without a compilation step, all with zero dependencies. The size of the libraries is only 10k to 20k bigger than jQuery. If you need even less bytes, then Preact is also an option (also with htm [1]), and it clocks at around 3k + 400 bytes for htm. If you're only targeting modern browsers with ES6 support you can even use `import from` statements. [1] https://github.com/developit/htm
In On Modern Web Applications Stability
> I suppose I could rephrase my question to something like "What is the point of this library?" It's just a lightweight, no-build-steps-required library that's similar to React. If you already like using React there's nothing much compelling to make you switch. I like using it with HTM for a nice alternative to JSX which doesn't need any build steps. I can't speak on its interaction with TypeScript, I've only used this for simple pages where I want to add some interactivity without involving the rest of the nightmarish JS ecosystem. https://github.com/developit/htm
In A little bit of plain JavaScript can do a lot
TL;DR: the idea is basically to write the Django data from the DB into a JS object and then use that to feed Vue components. I imagine they do this only for the stuff that uses Vue and not the whole page markup. Vue is a great option to combine with server rendered markup (PHP, Python, etc) because it can read the templates directly from the DOM and doesn't need a build step like JSX does. It's not the only option though. You could also use Preact + Htm (JSX in string templates) which doesn't need a build step either and is much smaller than Vue. https://github.com/developit/htm
In Using VueJS Alongside Django

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.