{"id":15416545,"url":"https://github.com/jahilldev/hypnode","last_synced_at":"2025-04-19T14:33:19.723Z","repository":{"id":40795574,"uuid":"224861410","full_name":"jahilldev/hypnode","owner":"jahilldev","description":"Generate HTML node trees from JSX or direct function calls","archived":false,"fork":false,"pushed_at":"2023-01-06T13:47:04.000Z","size":1372,"stargazers_count":6,"open_issues_count":13,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-29T08:43:31.178Z","etag":null,"topics":["architecture","components","es6","javascript","jsx","lightweight","micro-framework","react-alternative","server-side-rendering","typescript","webcomponents"],"latest_commit_sha":null,"homepage":null,"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/jahilldev.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}},"created_at":"2019-11-29T13:39:57.000Z","updated_at":"2024-03-09T18:38:42.000Z","dependencies_parsed_at":"2023-02-06T04:45:45.859Z","dependency_job_id":null,"html_url":"https://github.com/jahilldev/hypnode","commit_stats":null,"previous_names":["jhdevuk/hypnode"],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jahilldev%2Fhypnode","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jahilldev%2Fhypnode/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jahilldev%2Fhypnode/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jahilldev%2Fhypnode/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jahilldev","download_url":"https://codeload.github.com/jahilldev/hypnode/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249715156,"owners_count":21314988,"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":["architecture","components","es6","javascript","jsx","lightweight","micro-framework","react-alternative","server-side-rendering","typescript","webcomponents"],"created_at":"2024-10-01T17:12:21.066Z","updated_at":"2025-04-19T14:33:19.706Z","avatar_url":"https://github.com/jahilldev.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"A super fast, lightweight (roughly **1kb** gzipped) and reactive series of utility functions, used to build HTML node trees and stateful functional components. Can be used either directly via the `h` function, or from transpiled `JSX`.\n\nDue to it's size, `hypnode` is a useful companion utility for writing _WebComponents_, simplifying `HTML` structures, element references and state management. See section entitled \"WebComponents\" for an example, [click to jump there](#webcomponents).\n\n# Getting Started\n\nTo install `hypnode`, you can use one of the following in your project:\n\n`yarn add hypnode` or `npm install hypnode`\n\n`hypode` can be used in one of two ways, either as a target for `JSX` transpilation, or directly using the exposed `h` function. It's exported as ES6, so if you need to support older environments, you'll need to transpile down to ES5 in your build tasks.\n\nThe `h` function can be imported in one of the following ways:\n\n```javascript\nimport { h } from 'hypnode';\n```\n\n```javascript\nconst { h } = require('hypnode');\n```\n\n# Direct Usage\n\nOnce imported, use the function to generate your tree of DOM Nodes. The function takes 3 arguments, the last two of which are optional:\n\n```\nh([type]: string | Function, [attributes]?: object, [children]?: array[]);\n```\n\n## Simple Example\n\nThe code below:\n\n```javascript\nimport { h, render } from 'hypnode';\n\n/*[...]*/\n\nconst result = render(\n  h('div', { title: 'A DIV!' }, [\n    h('h1', { class: 'title' }, 'Hypnode'),\n    h('p', { id: 'text'}, 'My text value'),\n  )\n);\n\nconsole.log(result.outerHTML);\n```\n\nWill produce the following:\n\n```html\n\u003cdiv title=\"A DIV!\"\u003e\n  \u003ch1 class=\"title\"\u003eHypnode\u003c/h1\u003e\n  \u003cp id=\"text\"\u003eMy text value\u003c/p\u003e\n\u003c/div\u003e\n```\n\n# JSX Elements\n\n`hypnode` can be used with `JSX` to provide a more familiar API when building DOM structures. This will need a transpilation step, see below for examples.\n\n## TypeScript\n\nTranspilation of `JSX` is provided out of the box by custom factories (TypeScript 1.8+), to apply this, add the following to your `tsconfig.json` file:\n\n```json\n\"compilerOptions\": {\n   \"jsx\": \"react\",\n   \"jsxFactory\": \"h\",\n   /*[...]*/\n}\n```\n\nThis tells the TypeScript compiler to convert all `JSX` elements into function calls, in this case using our exported `h` function. You'll still need to import the `h` function in every file where you're using `JSX`.\n\nTo apply the correct types, all files that contain `JSX` must have the extension `.tsx`.\n\n## Simple Example\n\nThe code below:\n\n```javascript\nimport { h, render } from 'hypnode';\n\n/*[...]*/\n\nconst root = document.getElementId('root');\n\nconst result = render(\n  \u003cdiv class=\"wrapper\"\u003e\n    \u003ca id=\"link\" onClick={(ev = console.log(ev))}\u003e\n      Click here\n    \u003c/a\u003e\n  \u003c/div\u003e\n);\n\nroot.appendChild(result);\n```\n\nWill produce the following:\n\n```html\n\u003cdiv class=\"wrapper\"\u003e\n  \u003ca id=\"link\"\u003e\n    Click here\n  \u003c/a\u003e\n\u003c/div\u003e\n```\n\n# Rendering\n\nAs the `render()` function exported by `hypnode` returns a fully formed `HTMLElement`, you can handle it's output easily using native `DOM` API's like `root.appendChild` or `root.replaceChild`. There is, however, an optional secondary argument that can handle this for you, e.g:\n\n```javascript\nconst result = h('div', { class: 'wrapper' }, 'Lorem ipsum');\n\n/*[...]*/\n\nrender(result, document.getElementById('root'));\n```\n\nor, with `JSX`:\n\n```javascript\nconst result = \u003cdiv class=\"wrapper\"\u003eLorem ipsum\u003c/div\u003e;\n\n/*[...]*/\n\nrender(result, document.getElementById('root'));\n```\n\n# Event Binding\n\n`hypnode` provides a set of properties for you to apply DOM events. All native events are supported, formatted in camelCase and prefixed with `on`. For example:\n\n```javascript\nh('a', { onClick: (ev) =\u003e console.log(ev) }, 'Click Here');\n```\n\nor, with `JSX`:\n\n```javascript\n\u003cinput onKeyUp={(ev) =\u003e console.log(ev)} /\u003e\n```\n\n# Element References\n\nIf you need access to a particular node in your tree, use the `ref` property. For example:\n\n```javascript\nlet myElement;\n\n/*[...]*/\n\nh('div', { id: 'container' }, [\n  h('p', { ref: (el) =\u003e (myElement = el) }, 'Lorem ipsum dolor sit amet, consectetur'),\n]);\n```\n\nor with `JSX`:\n\n```javascript\nlet myElement;\n\n/*[...]*/\n\n\u003cdiv class=\"wrapper\"\u003e\n  \u003ca href=\"//link.co\" ref={(el) =\u003e (myElement = el)}\u003e\n    Click here\n  \u003c/a\u003e\n\u003c/div\u003e;\n```\n\n# Components\n\n`hypnode` can be used to create re-usable, functional components, below is a simple example:\n\n```javascript\nimport { h, render } from 'hypnode';\n\n/*[...]*/\n\nfunction Button({ className = '', children }) {\n  return h('a', { class: `button ${className}` }, children);\n}\n\n/*[...]*/\n\nconst button = h(Button, { className: 'big' }, buttonText));\n\nrender(button, document.getElementById('root'))\n```\n\nor with `JSX`:\n\n```javascript\nimport { h, render } from 'hypnode';\n\n/*[...]*/\n\nfunction Button({ className = '', children }) {\n  return \u003ca class={`button ${className}`}\u003e{children}\u003c/a\u003e;\n}\n\n/*[...]*/\n\nconst button = \u003cButton className=\"big\"\u003eClick here\u003c/Button\u003e;\n\nrender(button, document.getElementById('root'));\n```\n\n## WebComponents\n\nCreating and managing complex HTML structures using _WebComponents_ can become tricky as their size increases. `hypnode` simplifies this by incorporating a familiar component and state pattern into your custom elements. You can find more info on _WebComponents_ [here](https://www.webcomponents.org/introduction). As `hypnode` is fast and lightweight, _WebComponents_ can be more easily shared between projects without significant dependency overhead.\n\nA quick example can be found below:\n\n```javascript\n// myComponent.tsx (TypeScript + JSX)\n\nimport { h, render, useState, State } from  'hypnode';\n\n/*[...]*/\n\nclass MyComponent extends HTMLElement {\n  private state: State\u003cnumber\u003e;\n\n  public connectedCallback() {\n    const Button = () =\u003e this.renderButton();\n\n    this.appendChild(render(\u003cButton  /\u003e));\n  }\n\n  private  renderButton = () =\u003e {\n    const [counter] = (this.state =  useState(0));\n\n    return (\n      \u003cdiv class=\"my-component\"\u003e\n        \u003cp\u003eCounter: {counter}\u003c/p\u003e\n        \u003cbutton onClick={this.onClick}\u003eClick Here\u003c/button\u003e\n      \u003c/div\u003e\n    );\n  }\n\n  private onClick = (ev: Event) =\u003e {\n    const [counter, setState] = this.state;\n\n    setState(counter + 1);\n  }\n}\n```\n\n# State\n\n`hypnode` exposes a simple, declarative hook to provide state into your functional application.\n\nFirst, you'll need to import the hook function:\n\n```javascript\nimport { h, useState } from 'hypnode';\n```\n\nOnce imported, you can initialize a state registry in your components by doing the following:\n\n```javascript\nconst [state, setState] = useState(([value]: any));\n```\n\nThe `useState` function takes a single argument, the initial value you wish to assign to the state. This can be anything, a primitive or something more complex like an object. For example:\n\n```javascript\nfunction Button({ buttonText }) {\n  const [state, setState] = useState(10);\n\n  return h('button', { onClick: () =\u003e setState(state + 1) }, `${buttonText}: ${state}`);\n}\n```\n\nYou provide mutations to your state via the `setState` function, this accepts a _new_ value you wish to assign. Whenever this function is called, the component will be re-rendered with the replaced state value.\n\n# Effects\n\n`hypnode` exports a simple effect hook, `useEffect`. This takes a callback as it's only argument which will be called on \"mount\". You can optionally return another function from it that will be called on \"un-mount\". The lifecycle of this function works in a similar way to React's hook by the same name.\n\nSee example below:\n\n```javascript\nimport { h, useEffect } from 'hypnode';\n\n/*[...]*/\n\nfunction Banner({ children }) {\n  useEffect(() =\u003e {\n    console.log('onMount');\n\n    return () =\u003e console.log('onUnMount (optional)');\n  });\n\n  return h('div', { class: 'banner' }, children);\n}\n```\n\n# Server Side Rendering\n\n`hypnode` provides a Virtual `DOM` representation for server side rendering (universal rendering). You can use this output to generate a complete `HTML` representation of your app. A prebuilt utility that can convert this into an `HTML` string can be found here: [`hypnode-server`](https://github.com/jhdevuk/hypnode-server)\n\n# TypeScript\n\nThis utility was created with TypeScript and comes pre-bundled with a definition file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjahilldev%2Fhypnode","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjahilldev%2Fhypnode","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjahilldev%2Fhypnode/lists"}