{"id":17446026,"url":"https://github.com/jamen/h2spec","last_synced_at":"2026-01-12T06:41:47.807Z","repository":{"id":96784567,"uuid":"93969514","full_name":"jamen/h2spec","owner":"jamen","description":"A specification for proper h() calls","archived":false,"fork":false,"pushed_at":"2017-12-05T08:59:43.000Z","size":10,"stargazers_count":45,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-02-08T01:48:52.473Z","etag":null,"topics":["dom","h","h2","html","spec","virtual-dom"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jamen.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"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":"2017-06-10T22:48:52.000Z","updated_at":"2021-12-19T15:34:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"b69c1d67-a55e-4506-8e87-bda09195cd70","html_url":"https://github.com/jamen/h2spec","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamen%2Fh2spec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamen%2Fh2spec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamen%2Fh2spec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamen%2Fh2spec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jamen","download_url":"https://codeload.github.com/jamen/h2spec/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246802594,"owners_count":20836365,"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":["dom","h","h2","html","spec","virtual-dom"],"created_at":"2024-10-17T18:20:53.642Z","updated_at":"2026-01-12T06:41:47.778Z","avatar_url":"https://github.com/jamen.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# h2spec (WIP)\n\u003e A specification for proper `h()` calls.\n\n## Abstract\n\nLibraries such as [`hyperapp`](https://github.com/hyperapp), [`hyperscript`](https://github.com/hyperhype/hyperscript), [`choo`](https://github.com/yoshuawuyts/choo) and [`snabbdom`](https://github.com/snabbdom/snabbdom) often feature a notable discrepancy in their implementations of the `h()` function. The goal of `h2spec` is to revise and standardize the signature for `h()` functions under the name \"h2\" or \"hyper2\". These projects make the usage consistent no matter what view you're working with: DOM, virtual DOM, server rendering, terminal, canvas, etc. The spec itself is oriented around simplicity, usability, and ease of implementation.\n\nOnce the spec is more mature, several of these libraries will be forked and aligned with the spec. Patches will be sent upstream where it can be merged/rejected by the authors.  But, there will also be several \"official\" implementations before this as a proof-of-concept. Ones that get rejected may be maintained on their own.\n\n## Specification\n\n### `h(tag, data?, children?) -\u003e node`\n\n1. `tag`: a string denoting the desired tag name. Cannot contain extra data like classes or ids (e.g. `div.foo` or `div#bar`).\n2. `data` (optional): a plain JavaScript object which maps attributes to values, otherwise `null` or `undefined`.\n3. `children` (optional): an array of `node` objects (i.e. whatever the `h` function in question returns) and/or _primitive values_.\n\nA primitive value is a boolean, number, string, `null`, or `undefined` (as specified [by ECMAScript](https://www.ecma-international.org/ecma-262/5.1/#sec-4.3.2)).\n\n## Examples\n\n```js\nh('br')\nh('div', { foo: 'bar' }, [ 'baz' ])\nh('span', null, [ 'foo' ])\nh('header', null, [\n  h('h1', null, [ 'hello world' ]),\n  h('nav', null, [\n    h('a', { href: '#foo' }, [ 'foo' ]),\n    h('a', { href: '#bar' }, [ 'bar' ]),\n    h('a', { href: '#baz' }, [ 'baz' ])\n  ])\n])\n```\n\n## Projects\n\n - [`h2spec`](https://github.com/hyper2/h2spec) (this)\n - [`h2dom`](https://github.com/hyper2/h2dom) creates DOM nodes\n - [`h2ml`](https://github.com/hyper2/h2ml) creates HTML strings\n - [`h2array`](https://github.com/hyper2/h2json) creates array trees resembling `h()` calls\n\n## FAQ\n\n### Should the return types of `h`-libraries (DOM, VDOMs, strings, etc) cross into each other?\n\nThis spec isolates `h` functions' children to their own return type for a reason.\nDo not mix return types outside of something experimental.\nHowever, you can change your entire project tree to DOM, VDOM, and strings, because the elements created are compatible.\n\nElements are symbolized through combining `{ tag, data, children }`.\nThe `h(tag, data?, children?)` function is what ties the production of a DOM node, VDOM object, string, or anything, together with consistent usage under that simple combination.\n\nWhile some of these return types do mix well (i.e. VDOMs + strings = SSR) most do not. Handling several content types in each creates needless complexity. This is exactly why `h(...)` should be very well defined in itself, so it is easy to swap out whole trees, because the libraries rely on the same `h` function usage.\n\n### How would a VDOM or JSON abstraction of this look?\n\nSince the elements are only tied together through `tag`, `data`, and `children`, you could just plop those into objects or arrays:\n\n```js\n{\n  tag: 'div',\n  data: { class: 'foo' },\n  children: [\n    { tag: 'div', data: null, children: [ 'foo' ] },\n    { tag: 'span', data: null, children: [ 'bar' ] },\n    // ...\n  ]\n}\n```\n\nor more compact\n\n```js\n[ 'div', { class: 'foo' }, [\n  [ 'div', null, [ 'foo' ] ],\n  [ 'span', null, [ 'bar' ] ]\n]]\n```\n\nwhich could then map directly to `h()` calls:\n\n```js\nh('div', { class: 'foo' }, [\n  h('div', null, [ 'foo' ]),\n  h('span', null, [ 'bar' ])\n])\n```\n\nThis is possible because the spec limits trees to a single node type, so you can guarantee the `h(...)` function will be the same for every node.\n\n### How strict is the spec?\n\nSome conditions are critical, such as parameter precedence, but others are simple assertions that can be \"reasonably ignored\" for now to create smaller implementation sizes. For example, checking primitive types and array contents every time can be costly, so they can be assumed. But, an implementation should never support something outside of what the spec allows.\n\nWe may create fuzztesters to ensure compatbility as the spec gets more mature.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamen%2Fh2spec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjamen%2Fh2spec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamen%2Fh2spec/lists"}