{"id":19651530,"url":"https://github.com/herp-inc/snabbdom-jsx","last_synced_at":"2025-09-07T21:10:17.720Z","repository":{"id":37077429,"uuid":"388826238","full_name":"herp-inc/snabbdom-jsx","owner":"herp-inc","description":"Yet another JSX pragma for Snabbdom","archived":false,"fork":false,"pushed_at":"2024-12-23T18:17:53.000Z","size":929,"stargazers_count":4,"open_issues_count":13,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-17T07:11:39.405Z","etag":null,"topics":["jsx","snabbdom"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@herp-inc/snabbdom-jsx","language":"TypeScript","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/herp-inc.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":"2021-07-23T14:20:58.000Z","updated_at":"2024-11-29T13:42:15.000Z","dependencies_parsed_at":"2024-02-16T19:30:04.289Z","dependency_job_id":"02137fb2-6d42-4bc2-8967-ec8e3c6ef0e9","html_url":"https://github.com/herp-inc/snabbdom-jsx","commit_stats":null,"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"purl":"pkg:github/herp-inc/snabbdom-jsx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/herp-inc%2Fsnabbdom-jsx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/herp-inc%2Fsnabbdom-jsx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/herp-inc%2Fsnabbdom-jsx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/herp-inc%2Fsnabbdom-jsx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/herp-inc","download_url":"https://codeload.github.com/herp-inc/snabbdom-jsx/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/herp-inc%2Fsnabbdom-jsx/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274095422,"owners_count":25221433,"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","status":"online","status_checked_at":"2025-09-07T02:00:09.463Z","response_time":67,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["jsx","snabbdom"],"created_at":"2024-11-11T15:06:56.806Z","updated_at":"2025-09-07T21:10:17.689Z","avatar_url":"https://github.com/herp-inc.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @herp-inc/snabbdom-jsx [![npm](https://img.shields.io/npm/v/@herp-inc/snabbdom-jsx)](https://www.npmjs.com/package/@herp-inc/snabbdom-jsx)\n\nYet another [JSX](https://facebook.github.io/jsx/) pragma for [Snabbdom](https://www.npmjs.com/package/snabbdom)\n\n## Features\n\n- Straightforward and intuitive syntax\n  - `\u003cinput type=\"text\" /\u003e` rather than `\u003cinput props={{ type: 'text' }}\u003e`\n- Typechecked attributes on intrinsic elements\n  - Only for HTML elements for now\n- Typechecked children\n- `className` and `id` will be the part of the [`sel`](https://github.com/snabbdom/snabbdom#sel--string)\n- [Type-safe custom modules via module augmentation](#custom-modules)\n- Support for [React 17 style automatic runtime](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html)\n\n## Example\n\n```tsx\nconst vnode = (\n  \u003cdiv id=\"container\" className=\"two classes\" onclick={someFn}\u003e\n    \u003cspan $style={{ fontWeight: 'bold' }}\u003eThis is bold\u003c/span\u003e and this is just normal text\n    \u003ca href=\"/foo\"\u003eI'll take you places!\u003c/a\u003e\n  \u003c/div\u003e\n);\n```\n\n## Installation\n\nNote that the following packages are peer dependencies of this library, which need to be installed separately.\n\n| Package                                              | Version |\n| ---------------------------------------------------- | ------- |\n| [`csstype`](https://www.npmjs.com/package/csstype)   | `3`     |\n| [`snabbdom`](https://www.npmjs.com/package/snabbdom) | `3`     |\n\n### With [npm](https://www.npmjs.com/)\n\n```sh\n$ npm install @herp-inc/snabbdom-jsx\n```\n\n### With [yarn](https://yarnpkg.com/)\n\n```sh\n$ yarn add @herp-inc/snabbdom-jsx\n```\n\n## Usage\n\nNote that fragments are still experimental. Make sure you are using Snabbdom v3.2+ and opt it in to enable the feature.\n\n```ts\nconst patch = init(modules, undefined, {\n  experimental: {\n    fragments: true,\n  },\n});\n```\n\n### With [TypeScript](https://www.typescriptlang.org/)\n\nAdd the following options to your `tsconfig.json`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"jsx\": \"react-jsx\",\n    \"jsxImportSource\": \"@herp-inc/snabbdom-jsx\"\n  }\n}\n```\n\n### With [Babel](https://babeljs.io/)\n\nAdd [`@babel/plugin-transform-react-jsx`](https://www.npmjs.com/package/@babel/plugin-transform-react-jsx) to your `devDependencies`.\n\nAdd the following options to your Babel configuration:\n\n```json\n{\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-react-jsx\",\n      {\n        \"importSource\": \"@herp-inc/snabbdom-jsx\",\n        \"runtime\": \"automatic\"\n      }\n    ]\n  ]\n}\n```\n\n## Attributes mapping\n\nBy default, an attribute will be passed to [the props module](https://github.com/snabbdom/snabbdom#the-props-module).\n\n```tsx\n\u003cinput type=\"text\" /\u003e\n// { props: { type: 'text' } }\n```\n\nHowever, certain attributes will be treated differently.\n\n### `className` and `id`\n\n`className` and `id` attributes will be concatenated to the [`sel`](https://github.com/snabbdom/snabbdom#sel--string) with `.` and `#` respectively, and won't be passed to any modules. For example, the expression `\u003cdiv id=\"foo\" className=\"bar baz\" /\u003e` will yield a virtual node with `{ sel: 'div#foo.bar.baz' }`\n\n### `aria-*`\n\nAn attribute starting with `aria-` will be passed to [the attributes module](https://github.com/snabbdom/snabbdom#the-attributes-module).\n\n```tsx\n\u003cbutton aria-label=\"Send\" /\u003e\n// { attrs: { 'aria-label': 'Send' } }\n```\n\n### `data-*`\n\nAn attribute starting with `data-` will be passed to [the dataset module](https://github.com/snabbdom/snabbdom#the-dataset-module). Note that the `data-` prefix will be removed and dashes will be converted to camel case.\n\n```tsx\n\u003cdiv data-foo-bar=\"baz\" /\u003e\n// { dataset: { fooBar: 'baz' } }\n```\n\n### `is`\n\nThe `is` attribute can be used when you want to instantiate your customized built-in elements.\n\n```tsx\n\u003cdiv is=\"custom-element\" /\u003e\n// { is: 'custom-element' }\n```\n\n### `on*`\n\nAn attribute starting with `on` will passed to [the event listeners module](https://github.com/snabbdom/snabbdom#the-eventlisteners-module).\n\n```tsx\n\u003cdiv\n  onclick={(e) =\u003e {\n    console.log(e);\n  }}\n/\u003e\n// { on: { click: f } }\n```\n\n### `list`, `role`, and `popoverTarget`\n\nThe `list`, the `role`, and the `popoverTarget` attributes will be passed to [the attributes module](https://github.com/snabbdom/snabbdom#the-attributes-module).\nNote that the attribute names will be lowercased.\n\n```tsx\n\u003cdiv role=\"button\" /\u003e\n// { attrs: { role: 'button' } }\n\n\u003cinput list=\"options\" /\u003e\n// { attrs: { list: 'options' } }\n\n\u003cbutton popoverTarget=\"popover\" /\u003e\n// { attrs: { popovertarget: 'popover' } }\n```\n\n### `$hook`\n\nThe `$hook` attribute is treated as [hooks](https://github.com/snabbdom/snabbdom#hooks).\n\n```tsx\n\u003cdiv\n  $hook={{\n    insert(vnode) {\n      console.log(vnode);\n    },\n  }}\n/\u003e\n// { hook: { insert: f } }\n```\n\nFor the sake of backward compatibility, `hook` (without the dollar sign) also behaves the same. However it is deprecated and will be removed in the future.\n\n### `$key`\n\nThe `$key` attribute is treated as [a key](https://github.com/snabbdom/snabbdom#key--string--number).\n\n```tsx\n\u003cdiv $key=\"foo\" /\u003e\n// { key: 'foo' }\n```\n\nFor the sake of backward compatibility, `key` (without the dollar sign) also behaves the same. However it is deprecated and will be removed in the future.\n\n### SVG elements\n\nAttributes of `\u003csvg\u003e` and its descendant elements are passed to [the attributes module](https://github.com/snabbdom/snabbdom#the-attributes-module).\n\n### Built-in modules\n\nIn Snabbdom, different functionalities are delegated to separate modules. Values can be passed to them via attributes starting with `$`.\n\n#### `$attrs` ([the attributes module](https://github.com/snabbdom/snabbdom#the-attributes-module))\n\n```tsx\n\u003cdiv $attrs={{ class: 'foo' }} /\u003e\n// { attrs: { class: 'foo' } }\n```\n\n#### `$class` ([the class module](https://github.com/snabbdom/snabbdom#the-class-module))\n\n```tsx\n\u003cdiv $class={{ foo: true }} /\u003e\n// { class: { foo: true } }\n```\n\n#### `$dataset` ([the dataset module](https://github.com/snabbdom/snabbdom#the-dataset-module))\n\n```tsx\n\u003cdiv $dataset={{ foo: 'bar' }} /\u003e\n// { dataset: { foo: 'bar' } }\n```\n\n#### `$on` ([the event listeners module](https://github.com/snabbdom/snabbdom#the-eventlisteners-module))\n\n```tsx\n\u003cdiv\n  $on={{\n    click: (e) =\u003e {\n      console.log(e);\n    },\n  }}\n/\u003e\n// { on: { click: f } }\n```\n\n#### `$props` ([the props module](https://github.com/snabbdom/snabbdom#the-props-module))\n\n```tsx\n\u003cdiv $props={{ className: 'foo' }} /\u003e\n// { props: { className: 'foo' } }\n```\n\n#### `$style` ([the style module](https://github.com/snabbdom/snabbdom#the-style-module))\n\n```tsx\n\u003cdiv $style={{ opacity: '0', delayed: { opacity: '1' }, remove: { opacity: '0' } }} /\u003e\n// { style: { opacity: '0', delayed: { opacity: '1' }, remove: { opacity: '0' } } }\n```\n\n#### Aliases\n\nFor the sake of backward compatibility, the following aliases are also defined. However they are deprecated and will be removed in the future.\n\n| Attribute  | Alias(es)         |\n| ---------- | ----------------- |\n| `$attrs`   | `attrs`           |\n| `$class`   | `class`           |\n| `$dataset` | `data`, `dataset` |\n| `$on`      | `on`              |\n| `$props`   | `props`           |\n| `$style`   | `style`           |\n\n### Custom modules\n\nJust like built-in modules, you can pass an arbitrary value to your custom modules via an attribute starting with `$`. For example, the expression `\u003cdiv $custom={{ foo: 'bar' }} /\u003e` will yield `{ custom: { foo: 'bar' } }`.\n\n#### Note for TypeScript users\n\nUnlike built-in modules, we have no assumptions on what kind of values should be passed to custom modules. You have to augment `jsx.CustomModules` interface so that it will typecheck.\n\n```ts\ndeclare module '@herp-inc/snabbdom-jsx/jsx-runtime' {\n  namespace jsx {\n    interface CustomModules {\n      // Add your custom modules here\n      custom: {\n        foo: string;\n      };\n    }\n  }\n}\n```\n\n## Components\n\nA JSX component can be defined with a function with the signature of `\u003cProps\u003e(props: Props) =\u003e Snabbdom.VNodeChildElement`.\n\n```tsx\nimport type Snabbdom from '@herp-inc/snabbdom-jsx';\n\ntype Props = {\n  children: Snabbdom.Node;\n  name: string;\n};\n\nconst Component: Snabbdom.Component\u003cProps\u003e = ({ children, name }) =\u003e (\n  \u003cdiv\u003e\n    Hello, {name}!\u003cdiv\u003e{children}\u003c/div\u003e\n  \u003c/div\u003e\n);\n\nconst vnode = \u003cComponent /\u003e;\n```\n\n## Caveats\n\n- `boolean`, `null`, and `undefined` values are not be filtered out of the tree but rendered as comment nodes (for the sake of correct diffing)\n- `snabbdom-pragma`-style `MODULE-PROPERTY` notation is not supported.\n\n## Acknowledgements\n\nThe code base is based on these libraries:\n\n- [`snabbdom`](https://www.npmjs.com/package/snabbdom)\n- [`snabbdom-pragma`](https://www.npmjs.com/package/snabbdom-pragma)\n- [`@types/react`](https://www.npmjs.com/package/@types/react)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fherp-inc%2Fsnabbdom-jsx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fherp-inc%2Fsnabbdom-jsx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fherp-inc%2Fsnabbdom-jsx/lists"}