{"id":13394207,"url":"https://github.com/developit/htm","last_synced_at":"2025-05-14T22:04:05.333Z","repository":{"id":37444865,"uuid":"142916901","full_name":"developit/htm","owner":"developit","description":"Hyperscript Tagged Markup: JSX alternative using standard tagged templates, with compiler support.","archived":false,"fork":false,"pushed_at":"2024-02-01T21:36:52.000Z","size":377,"stargazers_count":8831,"open_issues_count":45,"forks_count":175,"subscribers_count":71,"default_branch":"master","last_synced_at":"2025-04-30T18:38:36.875Z","etag":null,"topics":["babel","babel-plugin","jsx","tagged-template","virtual-dom"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/developit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-07-30T19:04:49.000Z","updated_at":"2025-04-30T14:21:28.000Z","dependencies_parsed_at":"2022-07-08T08:04:29.934Z","dependency_job_id":"88a3143f-c3ed-4c8f-a67e-f5988f7fdcb1","html_url":"https://github.com/developit/htm","commit_stats":{"total_commits":290,"total_committers":34,"mean_commits":8.529411764705882,"dds":0.6827586206896552,"last_synced_commit":"d62dcfdc721e47bc1923a2cb7a01ebd594ab0c25"},"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developit%2Fhtm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developit%2Fhtm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developit%2Fhtm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developit%2Fhtm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/developit","download_url":"https://codeload.github.com/developit/htm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252368994,"owners_count":21736868,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["babel","babel-plugin","jsx","tagged-template","virtual-dom"],"created_at":"2024-07-30T17:01:12.465Z","updated_at":"2025-05-07T08:26:16.902Z","avatar_url":"https://github.com/developit.png","language":"JavaScript","readme":"\n\u003ch1 align=\"center\"\u003e\n  HTM (Hyperscript Tagged Markup)\n  \u003ca href=\"https://www.npmjs.org/package/htm\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/htm.svg?style=flat\" alt=\"npm\"\u003e\u003c/a\u003e\n\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://i.imgur.com/0ph8dbS.png\" width=\"572\" alt=\"hyperscript tagged markup demo\"\u003e\n\u003c/p\u003e\n\n`htm` is **JSX-like syntax in plain JavaScript** - no transpiler necessary.\n\nDevelop with React/Preact directly in the browser, then compile `htm` away for production.\n\nIt uses standard JavaScript [Tagged Templates] and works in [all modern browsers].\n\n## `htm` by the numbers:\n\n🐣 **\u003c 600 bytes** when used directly in the browser\n\n⚛️ **\u003c 500 bytes** when used with Preact _(thanks gzip 🌈)_\n\n🥚 **\u003c 450 byte** `htm/mini` version\n\n🏅 **0 bytes** if compiled using [babel-plugin-htm]\n\n\n## Syntax: like JSX but also lit\n\nThe syntax you write when using HTM is as close as possible to JSX:\n\n- Spread props: `\u003cdiv ...${props}\u003e` instead of `\u003cdiv {...props}\u003e`\n- Self-closing tags: `\u003cdiv /\u003e`\n- Components: `\u003c${Foo}\u003e` instead of `\u003cFoo\u003e` _(where `Foo` is a component reference)_\n- Boolean attributes: `\u003cdiv draggable /\u003e`\n\n\n## Improvements over JSX\n\n`htm` actually takes the JSX-style syntax a couple steps further!\n\nHere's some ergonomic features you get for free that aren't present in JSX:\n\n- **No transpiler necessary**\n- HTML's optional quotes: `\u003cdiv class=foo\u003e`\n- Component end-tags: `\u003c${Footer}\u003efooter content\u003c//\u003e`\n- Syntax highlighting and language support via the [lit-html VSCode extension] and [vim-jsx-pretty plugin].\n- Multiple root element (fragments): `\u003cdiv /\u003e\u003cdiv /\u003e`\n- Support for HTML-style comments: `\u003cdiv\u003e\u003c!-- comment --\u003e\u003c/div\u003e`\n\n## Installation\n\n`htm` is published to npm, and accessible via the unpkg.com CDN:\n\n**via npm:**\n\n```js\nnpm i htm\n```\n\n**hotlinking from unpkg:** _(no build tool needed!)_\n\n```js\nimport htm from 'https://unpkg.com/htm?module'\nconst html = htm.bind(React.createElement);\n```\n\n```js\n// just want htm + preact in a single file? there's a highly-optimized version of that:\nimport { html, render } from 'https://unpkg.com/htm/preact/standalone.module.js'\n```\n\n## Usage\n\nIf you're using Preact or React, we've included off-the-shelf bindings to make your life easier.\nThey also have the added benefit of sharing a template cache across all modules.\n\n```js\nimport { render } from 'preact';\nimport { html } from 'htm/preact';\nrender(html`\u003ca href=\"/\"\u003eHello!\u003c/a\u003e`, document.body);\n```\n\nSimilarly, for React:\n\n```js\nimport ReactDOM from 'react-dom';\nimport { html } from 'htm/react';\nReactDOM.render(html`\u003ca href=\"/\"\u003eHello!\u003c/a\u003e`, document.body);\n```\n\n### Advanced Usage\n\nSince `htm` is a generic library, we need to tell it what to \"compile\" our templates to.\nYou can bind `htm` to any function of the form `h(type, props, ...children)` _([hyperscript])_.\nThis function can return anything - `htm` never looks at the return value.\n\nHere's an example `h()` function that returns tree nodes:\n\n```js\nfunction h(type, props, ...children) {\n  return { type, props, children };\n}\n```\n\nTo use our custom `h()` function, we need to create our own `html` tag function by binding `htm` to our `h()` function:\n\n```js\nimport htm from 'htm';\n\nconst html = htm.bind(h);\n```\n\nNow we have an `html()` template tag that can be used to produce objects in the format we created above.\n\nHere's the whole thing for clarity:\n\n```js\nimport htm from 'htm';\n\nfunction h(type, props, ...children) {\n  return { type, props, children };\n}\n\nconst html = htm.bind(h);\n\nconsole.log( html`\u003ch1 id=hello\u003eHello world!\u003c/h1\u003e` );\n// {\n//   type: 'h1',\n//   props: { id: 'hello' },\n//   children: ['Hello world!']\n// }\n```\n\nIf the template has multiple element at the root level\nthe output is an array of `h` results:\n\n```js\nconsole.log(html`\n  \u003ch1 id=hello\u003eHello\u003c/h1\u003e\n  \u003cdiv class=world\u003eWorld!\u003c/div\u003e\n`);\n// [\n//   {\n//     type: 'h1',\n//     props: { id: 'hello' },\n//     children: ['Hello']\n//   },\n//   {\n//     type: 'div',\n//     props: { class: 'world' },\n//     children: ['world!']\n//   }\n// ]\n```\n\n### Caching\n\nThe 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:\n\n* Change your `h` function to copy nodes when needed.\n* Add the code `this[0] = 3;` at the beginning of your `h` function, which disables caching of created elements.\n* Use `htm/mini`, which disables caching by default.\n\n## Example\n\nCurious to see what it all looks like? Here's a working app!\n\nIt's a single HTML file, and there's no build or tooling. You can edit it with nano.\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n  \u003ctitle\u003ehtm Demo\u003c/title\u003e\n  \u003cscript type=\"module\"\u003e\n    import { html, Component, render } from 'https://unpkg.com/htm/preact/standalone.module.js';\n\n    class App extends Component {\n      addTodo() {\n        const { todos = [] } = this.state;\n        this.setState({ todos: todos.concat(`Item ${todos.length}`) });\n      }\n      render({ page }, { todos = [] }) {\n        return html`\n          \u003cdiv class=\"app\"\u003e\n            \u003c${Header} name=\"ToDo's (${page})\" /\u003e\n            \u003cul\u003e\n              ${todos.map(todo =\u003e html`\n                \u003cli key=${todo}\u003e${todo}\u003c/li\u003e\n              `)}\n            \u003c/ul\u003e\n            \u003cbutton onClick=${() =\u003e this.addTodo()}\u003eAdd Todo\u003c/button\u003e\n            \u003c${Footer}\u003efooter content here\u003c//\u003e\n          \u003c/div\u003e\n        `;\n      }\n    }\n\n    const Header = ({ name }) =\u003e html`\u003ch1\u003e${name} List\u003c/h1\u003e`\n\n    const Footer = props =\u003e html`\u003cfooter ...${props} /\u003e`\n\n    render(html`\u003c${App} page=\"All\" /\u003e`, document.body);\n  \u003c/script\u003e\n\u003c/html\u003e\n```\n\n[⚡️ **See live version** ▶](https://htm-demo-preact.glitch.me/)\n\n[⚡️ **Try this on CodeSandbox** ▶](https://codesandbox.io/s/x7pmq32j6q)\n\nHow nifty is that?\n\nNotice there's only one import - here we're using the prebuilt Preact integration since it's easier to import and a bit smaller.\n\nThe same example works fine without the prebuilt version, just using two imports:\n\n```js\nimport { h, Component, render } from 'preact';\nimport htm from 'htm';\n\nconst html = htm.bind(h);\n\nrender(html`\u003c${App} page=\"All\" /\u003e`, document.body);\n```\n\n## Other Uses\n\nSince `htm` is designed to meet the same need as JSX, you can use it anywhere you'd use JSX.\n\n**Generate HTML using [vhtml]:**\n\n```js\nimport htm from 'htm';\nimport vhtml from 'vhtml';\n\nconst html = htm.bind(vhtml);\n\nconsole.log( html`\u003ch1 id=hello\u003eHello world!\u003c/h1\u003e` );\n// '\u003ch1 id=\"hello\"\u003eHello world!\u003c/h1\u003e'\n```\n\n**Webpack configuration via [jsxobj]:** ([details here](https://webpack.js.org/configuration/configuration-languages/#babel-and-jsx)) _(never do this)_\n\n```js\nimport htm from 'htm';\nimport jsxobj from 'jsxobj';\n\nconst html = htm.bind(jsxobj);\n\nconsole.log(html`\n  \u003cwebpack watch mode=production\u003e\n    \u003centry path=\"src/index.js\" /\u003e\n  \u003c/webpack\u003e\n`);\n// {\n//   watch: true,\n//   mode: 'production',\n//   entry: {\n//     path: 'src/index.js'\n//   }\n// }\n```\n\n## Demos \u0026 Examples\n\n- [Canadian Holidays](https://github.com/pcraig3/hols): A full app using HTM and Server-Side Rendering\n- [HTM SSR Example](https://github.com/timarney/htm-ssr-demo): Shows how to do SSR with HTM\n- [HTM + Preact SSR Demo](https://gist.github.com/developit/699c8d8f180a1e4eed58167f9c6711be)\n- [HTM + vhtml SSR Demo](https://gist.github.com/developit/ff925c3995b4a129b6b977bf7cd12ebd)\n\n## Project Status\n\nThe original goal for `htm` was to create a wrapper around Preact that felt natural for use untranspiled in the browser. I wanted to use Virtual DOM, but I wanted to eschew build tooling and use ES Modules directly.\n\n This meant giving up JSX, and the closest alternative was [Tagged Templates]. So, I wrote this library to patch up the differences between the two as much as possible. The technique turns out to be framework-agnostic, so it should work great with any library or renderer that works with JSX.\n\n`htm` is stable, fast, well-tested and ready for production use.\n\n[Tagged Templates]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_templates\n[lit-html]: https://github.com/Polymer/lit-html\n[babel-plugin-htm]: https://github.com/developit/htm/tree/master/packages/babel-plugin-htm\n[lit-html VSCode extension]: https://marketplace.visualstudio.com/items?itemName=bierner.lit-html\n[vim-jsx-pretty plugin]: https://github.com/MaxMEllon/vim-jsx-pretty\n[vhtml]: https://github.com/developit/vhtml\n[jsxobj]: https://github.com/developit/jsxobj\n[hyperscript]: https://github.com/hyperhype/hyperscript\n[all modern browsers]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Browser_compatibility\n","funding_links":[],"categories":["JavaScript","babel","Typescript / Javascript","Similar libraries","Programming Languages","Web Based Development Options","Frameworks","Libraries"],"sub_categories":["Other Tools","JavaScript","Notable","HTML"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevelopit%2Fhtm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevelopit%2Fhtm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevelopit%2Fhtm/lists"}