{"id":14990277,"url":"https://github.com/anh-ld/nho","last_synced_at":"2025-10-24T09:37:25.678Z","repository":{"id":205228838,"uuid":"711421944","full_name":"anh-ld/nho","owner":"anh-ld","description":"📌 1KB Web Component Abstraction","archived":false,"fork":false,"pushed_at":"2024-07-16T19:40:26.000Z","size":2454,"stargazers_count":55,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-12T16:51:33.960Z","etag":null,"topics":["1kb","custom-component","lightweight","web-component"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/anh-ld.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":"2023-10-29T08:06:48.000Z","updated_at":"2025-08-21T09:06:46.000Z","dependencies_parsed_at":null,"dependency_job_id":"57430469-b40f-4db7-b151-ca301e15e60d","html_url":"https://github.com/anh-ld/nho","commit_stats":{"total_commits":29,"total_committers":1,"mean_commits":29.0,"dds":0.0,"last_synced_commit":"a0971be3c000325da782ac99e87421aaa64e202f"},"previous_names":["anh-ld/nho"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/anh-ld/nho","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anh-ld%2Fnho","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anh-ld%2Fnho/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anh-ld%2Fnho/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anh-ld%2Fnho/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anh-ld","download_url":"https://codeload.github.com/anh-ld/nho/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anh-ld%2Fnho/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279823674,"owners_count":26232226,"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-10-19T02:00:07.647Z","response_time":64,"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":["1kb","custom-component","lightweight","web-component"],"created_at":"2024-09-24T14:19:48.916Z","updated_at":"2025-10-24T09:37:25.648Z","avatar_url":"https://github.com/anh-ld.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"## 📌 Nho\n\nNho (`nhỏ` | `small` in `Vietnamese`) is a tiny library designed for easy Web Component development.\n\n### Why Nho?\n\n- Writing a Web Component (WC) using vanilla JavaScript can be such tedious. Alternatively, popular WC libraries can be overkill and overweighted (4KB+) for creating small components like a `\"Buy now\" button` or a `cart listing`.\n\n- `Nho` simplifies the process by staying lightweight, removing unnecessary APIs, and using a simple DOM diffing algorithm.\n\n### Features\n\n- `1.3KB` gzipped.\n- Simple API inspired from `Vue`.\n\n\n### Example\n- [album list](https://nho-example.netlify.app/) - [source](./example)\n\n### Limitation\n\n- In order to stay small, `Nho` skips few advanced features found in popular front-end frameworks like `key`, `Fragments`, `memo`. The DOM diffing algorithm is somewhat basic, but it is fast enough for small projects. If your components become too complex, consider other options.\n\n### Installation\n\n#### using `npm`\nFirst, run\n\n```\nnpm install nho\n```\n\nthen\n```js\nimport { Nho } from 'nho';\nclass MyCounterChild extends Nho {}\n```\n\n\n#### using `CDN`\nFirst, add `script` to the `html` file\n```html\n\u003cscript src=\"https://unpkg.com/nho\"\u003e\u003c/script\u003e\n```\n\nthen, add `script` to the `html` file\n\n```html\n\u003cscript\u003e\n  let Nho = nho.Nho;\n  class MyCounterChild extends Nho {}\n\u003c/script\u003e\n```\n\n### Usage\n\n```js\n/* main.js */\n\n/* declare global style. Styles will be injected to all Nho Elements */\nNho.style = `\n  .box {\n    background: blue;\n    color: yellow;\n  }\n`\n\nclass MyCounterChild extends Nho {\n  render(h) {\n    /* bind value from props */\n    return h`\u003cdiv\u003eChild: ${this.props.count}\u003c/div\u003e`\n  }\n}\n\nclass MyCounter extends Nho {\n  setup() {\n    /* this method runs before mount */\n\n    /* create component state using \"this.reactive\", state must be an object */\n    this.state = this.reactive({ count: 1 });\n\n    /* only use ref for storing DOM reference */\n    this.pRef = this.ref();\n\n    /* effect */\n    this.effect(\n      // effect value: fn -\u003e value\n      () =\u003e this.state.count,\n      // effect callback: fn(old value, new value)\n      (oldValue, newValue) =\u003e {\n        console.log(oldValue, newValue)\n      }\n    )\n  }\n\n  onMounted() {\n    /* this method runs after mount */\n    console.log('Mounted');\n  }\n\n  onUpdated() {\n    /* this method runs after each update. */\n    console.log('Updated');\n\n    /* P tag ref */\n    console.log('P Ref', this.pRef?.current);\n  }\n\n  onUnmounted() {\n    /* this method runs before unmount */\n    console.log('Before unmount');\n  }\n\n  addCount() {\n    /* update state by redeclaring its key-value. Avoid updating the whole state. */\n    this.state.count += 1;\n  }\n\n  render(h) {\n    /* this method is used to render */\n\n    /*\n      JSX template alike\n      - Must have only 1 root element\n      - Bind state / event using value in literal string\n      - Pass state to child element using props with 'p:' prefix\n     */\n    return h`\n      \u003cdiv class=\"box\"\u003e\n        \u003cp ref=${this.pRef}\u003eName: ${this.state.count}\u003c/p\u003e\n        \u003cbutton onclick=${this.addCount}\u003eAdd count\u003c/button\u003e\n        \u003cmy-counter-child p:count=${this.state.count + 5}\u003e\u003c/my-counter-child\u003e\n      \u003c/div\u003e\n    `\n  }\n}\n\ncustomElements.define(\"my-counter\", MyCounter);\ncustomElements.define(\"my-counter-child\", MyCounterChild);\n```\n\n```html\n/* index.html */\n\u003cmy-counter\u003e\u003c/my-counter\u003e\n```\n\n### Notice\n- **Avoid** using these below properties inside Nho Component since they are reversed Nho's properties.\n\nElement properties\n\n```\n_op, _ef, _ev, _sr, _ga, _nm, _sc, _p, _u, _h, _e, _t\n```\n\n```\nsetup, onMounted, onUnmounted, onUpdated, effect, ref, reactive, render\n```\n\nClass properties\n```\n_c, style\n```\n\n### How it works\n\n- It's better to dive into the code, but here is a quick sketch about how `Nho` works.\n\n![How Nho works](./hiw.webp)\n\n### Mentions\n\n- [Frontend Focus's #651 issue](https://frontendfoc.us/issues/651)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanh-ld%2Fnho","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanh-ld%2Fnho","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanh-ld%2Fnho/lists"}