{"id":15685894,"url":"https://github.com/kt3k/cell","last_synced_at":"2025-07-21T10:06:04.827Z","repository":{"id":244922429,"uuid":"816702345","full_name":"kt3k/cell","owner":"kt3k","description":"☯ A frontend tool for easily writing UI components. Cell encourages the use of event handlers and signals https://jsr.io/@kt3k/cell","archived":false,"fork":false,"pushed_at":"2024-10-21T16:19:31.000Z","size":299,"stargazers_count":11,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-09T15:05:11.875Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://kt3k.github.io/cell/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kt3k.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2024-06-18T08:41:30.000Z","updated_at":"2024-12-30T13:07:41.000Z","dependencies_parsed_at":"2024-10-22T15:57:43.474Z","dependency_job_id":null,"html_url":"https://github.com/kt3k/cell","commit_stats":null,"previous_names":["kt3k/cell"],"tags_count":32,"template":false,"template_full_name":null,"purl":"pkg:github/kt3k/cell","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kt3k%2Fcell","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kt3k%2Fcell/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kt3k%2Fcell/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kt3k%2Fcell/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kt3k","download_url":"https://codeload.github.com/kt3k/cell/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kt3k%2Fcell/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266278376,"owners_count":23904041,"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":[],"created_at":"2024-10-03T17:32:38.744Z","updated_at":"2025-07-21T10:06:04.795Z","avatar_url":"https://github.com/kt3k.png","language":"TypeScript","readme":"\u003cimg src=\"https://kt3k.github.io/cell/cell-logo.svg\" width=\"70\" alt=\"cell\" /\u003e\n\n# Cell v0.7.6\n\n\u003e A frontend UI tool, encourages local event handlers and signals\n\n## Features\n\n- Cell encourages **local event handlers** pattern\n- Cell encourages **signals** pattern for remote effects\n- **Lightweight** (**\u003c 1.5 kiB** gzipped)\n- **TypeScript** friendly\n\n## Live examples\n\nSee [the live demos](https://kt3k.github.io/cell).\n\n## TodoMVC\n\nTodoMVC implementation is also available\n[here](https://github.com/kt3k/cell-todomvc).\n\n## Install\n\n```\nnpx jsr add @kt3k/cell\n```\n\nOr, in Deno,\n\n```\ndeno add @kt3k/cell\n```\n\n## Hello world: How to use `on` helper\n\nThe below is an example of `cell` component. A `cell` component is a function of\nthe type `(ctx: Context) =\u003e string | undefined`.\n\n`Context` includes many handy helpers for implementing UI behavior easily and\nquickly.\n\nThe below example uses `on` helper, which registers the event handler to the\nmounted dom element, which is `\u003cbutton\u003e` element in this case.\n\n```ts\nimport { type Context, register } from \"@kt3k/cell\"\n\nfunction MyComponent({ on }: Context) {\n  on(\"click\", () =\u003e {\n    alert(\"hello\")\n  })\n}\n\nregister(MyComponent, \"js-hello\")\n```\n\n```html\n\u003cbutton class=\"js-hello\"\u003eClick\u003c/button\u003e\n```\n\nWhen you click this button, it alerts \"hello\".\n\n## Mirroring the inputs: How to use `query` helper\n\nThe next component shows how you can copy the input text into other dom element.\n\n`query` is helper to query by the selector inside your component.\n`query(\".dest\")` is equivalent of `el.querySelector(\".dest\")`.\n\n```ts\nimport { type Context, register } from \"@kt3k/cell\"\n\nfunction Mirroring({ on, query }: Context) {\n  on(\"input\", () =\u003e {\n    query(\".dest\").textContent = query(\".src\").value\n  })\n}\n\nregister(Mirroring, \"js-mirroring\")\n```\n\n```html\n\u003cdiv class=\"js-mirroring\"\u003e\n  \u003cinput class=\"src\" placeholder=\"type something\" /\u003e\n  \u003cp class=\"dest\"\u003e\u003c/p\u003e\n\u003c/div\u003e\n```\n\n## Event Delegation: The 2nd arg of `on` helper\n\nIf you pass a string (a selector) as the second argument of `on` function, the\nevent handler is only invoked when the event comes from the element which\nmatches the given selector.\n\n```ts\nimport { type Context, register } from \"@kt3k/cell\"\n\nfunction DelegateComponent({ on, query }: Context) {\n  on(\"click\", \".btn\", () =\u003e {\n    query(\".result\").textContext += \" .btn clicked!\"\n  })\n}\n\nregister(DelegateComponent, \"js-delegate\")\n```\n\n## Outside events: `onOutside` helper\n\nBy calling `onOutside(event, handler)`, you can handle the event outside of the\ncomponent's DOM.\n\nThis is convenient, for example, when you like to close the modal dialog when\nthe user clicking the outside of it.\n\n```ts\nimport { type Context, register } from \"@kt3k/cell\"\n\nfunction OutsideClickComponent({ onOutside }: Context) {\n  onOutside(\"click\", ({ e }) =\u003e {\n    console.log(\"The outside of my-component has been clicked!\")\n  })\n}\n\nregister(OutsideClickComponent, \"js-outside-click\")\n```\n\n## Using Cell directly from the browser\n\nThe below example shows how you can use `cell` directly in the browsers.\n\n```html\n\u003cscript type=\"module\"\u003e\n  import { register } from \"https://kt3k.github.io/cell/dist.min.js\"\n\n  function Mirroring({ on, query }) {\n    on(\"input\", () =\u003e {\n      query(\".dest\").textContent = query(\".src\").value\n    })\n  }\n\n  register(Mirroring, \"js-mirroring\")\n\u003c/script\u003e\n\u003cdiv class=\"js-mirroring\"\u003e\n  \u003cinput class=\"src\" placeholder=\"Type something\" /\u003e\n  \u003cp class=\"dest\"\u003e\u003c/p\u003e\n\u003c/div\u003e\n```\n\n## Use signals when making remote effect\n\n`cell` recommends handling event locally, but in many cases you would also need\nto make effects to remote elements.\n\nIf you need to affects the components in remote places (i.e. components not an\nancestor or decendant of the component), we commend using `signals` for\ncommunicating with them.\n\n`signals` are event emitter with values, whose events are triggered only when\nthe values are changed.\n\n```ts\nimport { Context, Signal } from \"@kt3k/cell\"\n\nconst sig = new Signal(0)\n\nfunction Component({ el, subscribe }: Context) {\n  subscribe(sig, (v) =\u003e {\n    el.textContent = `The value is ${v}`\n  })\n}\n\nsig.update(1)\nsig.update(2)\n```\n\n## Write test of components\n\nUse `@b-fuse/deno-dom` for polyfill `document` object. An example of basic test\ncase of a component looks like the below:\n\n```ts\nimport { DOMParser } from \"@b-fuze/deno-dom\"\nimport { assertEquals } from \"@std/assert\"\nimport { type Context, mount, register } from \"@kt3k/cell\"\n\nDeno.test(\"A test case of Component\", () =\u003e {\n  function Component({ el }: Context) {\n    el.textContent = \"a\"\n  }\n\n  register(Component, \"js-component\")\n\n  globalThis.document = new DOMParser().parseFromString(\n    `\u003cbody\u003e\u003cdiv class=\"js-component\"\u003e\u003c/div\u003e\u003c/body\u003e`,\n    \"text/html\",\n    // deno-lint-ignore no-explicit-any\n  ) as any\n  mount()\n  assertEquals(document.body.firstChild?.textContent, \"a\")\n})\n```\n\n## Prior art\n\n- [capsule](https://github.com/capsidjs/capsule)\n- [capsid](https://github.com/capsidjs/capsid)\n\n## Projects with similar concepts\n\n- [Flight](https://flightjs.github.io/) by twitter\n  - Not under active development\n- [eddy.js](https://github.com/WebReflection/eddy)\n  - Archived\n\n## History\n\n- 2024-06-18 Forked from capsule.\n\n## License\n\nMIT\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkt3k%2Fcell","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkt3k%2Fcell","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkt3k%2Fcell/lists"}