{"id":24819672,"url":"https://github.com/sebbekarlsson/plicit","last_synced_at":"2026-03-05T21:02:52.812Z","repository":{"id":254199591,"uuid":"837243294","full_name":"sebbekarlsson/plicit","owner":"sebbekarlsson","description":"Reactive UI framework","archived":false,"fork":false,"pushed_at":"2024-08-24T20:09:06.000Z","size":5860,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-04T00:51:36.080Z","etag":null,"topics":["frontend-framework","jsx","reactive","ui","ui-framework"],"latest_commit_sha":null,"homepage":"","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/sebbekarlsson.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":"2024-08-02T14:14:01.000Z","updated_at":"2024-09-03T11:30:45.000Z","dependencies_parsed_at":"2024-08-22T01:41:32.251Z","dependency_job_id":null,"html_url":"https://github.com/sebbekarlsson/plicit","commit_stats":null,"previous_names":["sebbekarlsson/plicit"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sebbekarlsson/plicit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sebbekarlsson%2Fplicit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sebbekarlsson%2Fplicit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sebbekarlsson%2Fplicit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sebbekarlsson%2Fplicit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sebbekarlsson","download_url":"https://codeload.github.com/sebbekarlsson/plicit/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sebbekarlsson%2Fplicit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279016921,"owners_count":26085908,"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-13T02:00:06.723Z","response_time":61,"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":["frontend-framework","jsx","reactive","ui","ui-framework"],"created_at":"2025-01-30T17:59:36.086Z","updated_at":"2025-10-13T20:30:51.233Z","avatar_url":"https://github.com/sebbekarlsson.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\" style=\"text-align: center;\"\u003e\n    \u003cimg width=\"150\" src=\"logo.png\"/\u003e\n    \u003ch1\u003ePlicit\u003c/h1\u003e\n    \u003ci\u003eA framework for building web user interfaces with explicitly defined reactivity\u003c/i\u003e\n\u003c/div\u003e\n\n--- \n\n#### Some unique features:\n * You have full control over the reactivity.  \n   \u003e You decide if a singe property / attribute should be reactive, or if an entire component should be reactive.\n * Reactivity is separated from the rendering.  \n   \u003e You can use reactivity \"outside\" of the component hierarchy.\n * Asynchronous components and synchronous components are treated the same.  \n   \u003e You don't need to treat async components in some special way... ( No **\\\u003cSuspense\\\u003e** needed! )\n\n---\n\n## Reactivity\n\n### Explicit Reactivity\nWhile some implicit reactivity is supported, this framework aims to provide full control over\nthe reactivity by giving you the ability to be explicit about it.\n\n\nAn example:\n```tsx\nconst Counter = () =\u003e {\n  const count = signal\u003cnumber\u003e(0)\n  \n  return (\n    \u003cdiv\u003e\n      \u003cspan\u003eThe counter is \u003c/span\u003e\n      { computedSignal(() =\u003e \u003cspan\u003e{count.get()}\u003c/span\u003e) } \n      \u003cbutton on={{ click: () =\u003e count.set(x =\u003e x + 1) }}\u003eincrement\u003c/button\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\u003e Here, we are explicitly saying the only one of the `\u003cspan\u003e` elements should react to changes. \n\u003e However, the dependencies are __automatically__ tracked.\n\n---\n\nTo summarize, we explicitly define an element to be reactive by wrapping it in a function.  \nDependencies of a `signal` are automatically tracked.\n\n\n### Asynchronous Reactivity\nPlicit has been developed with asynchronicity in mind.  \nComponents can be async, as well as VDOM children.\n\n#### Async Components\n```tsx\nconst HelloWorld = async () =\u003e {\n  await sleep(1000); // or do an API request or something :)\n  return \u003cdiv\u003eHello world!\u003c/div\u003e;\n}\n\nconst App = () =\u003e {\n  return \u003cdiv\u003e\n    \u003cHelloWorld/\u003e\n  \u003c/div\u003e\n}\n```\n\u003e Here, the `\u003cHelloWorld\u003e` component will begin rendering once the `sleep()` promise has been resolved.\n\nYou can also define a \"placeholder\" to render while the component is loading:\n```tsx\nconst App = () =\u003e {\n  return \u003cdiv\u003e\n    \u003cHelloWorld asyncFallback={() =\u003e \u003cspan\u003ePlease wait...\u003c/span\u003e}/\u003e\n  \u003c/div\u003e\n}\n```\n\u003e Here's a good place to put a spinner or some other cool animation!\n\n#### Async VDOM children\n```tsx\nconst App = () =\u003e {\n  return \u003cdiv\u003e\n    {\n      asyncSignal(async () =\u003e {\n        await sleep(1000);\n        return \u003cdiv\u003eHello world!\u003c/div\u003e\n      }, { fallback: () =\u003e \u003cspan\u003ePlease wait...\u003c/span\u003e })\n    }\n  \u003c/div\u003e\n}\n```\n\u003e This will give you a similar result as the previous example,  \n\u003e but instead of an async component, we're using an async signal.\n\n\n### Signals\nAs you might have noticed from the examples, signals are used for reactive states.  \n**If you're not familiar with signals**: a signal is basically a container for some data and it will automatically track other functions (or signals) who depends on it.\n\n#### Signals in Plicit\nSignals in Plicit might differ a bit from other implementations, so let's go through some examples.  \n\n##### Basic Counter\n```typescript\nconst counter = signal(0);\n\n// This will be triggered everytime the counter is changed.\neffect(() =\u003e console.log(counter.get()))\n\ncounter.set((count) =\u003e count + 1)\n```\n\n##### Computed\nThere is also something called __computed signals__ in Plicit, it's just a signal that transforms the value of another signal.\n```typescript\nconst name = signal\u003cstring\u003e('John Doe');\n\n// will update everytime `name` is changed\nconst reversedName = computedSignal(() =\u003e Array.from(name.get()).reverse().join(''));\n\n// A computed signal can also be defined like this:\nconst reversedName = signal(() =\u003e name.get().reverse(), { isComputed: true });\n```\n\n##### Async\nAn async signal works just like a regular signal, however it's able to be updated asynchronously. \n```typescript\nconst products = asyncSignal\u003cProduct[]\u003e(async () =\u003e {\n  const response = await fetch('https://somedomain.com/your/api/endpoint');\n  return await response.json();\n});\n\n// You can check whether or not the signal has finished, either by inspecting it's state,\n// or by having another signal react to it's changes.\n// However, inspecting it's state is not reactive.\n\n// Reactive, will be triggered when the promise is resolved\nconst productNames = computedSignal(() =\u003e {\n  return (products.get() || []).map(product =\u003e product.name)\n})\n\n// Not reactive\nif (products.state === ESignalState.RESOLVED) { doSomething() }\n\n```\nYou can also provide a fallback value and the signal will return this value if it hasn't been resolved yet\n```typescript\nconst products = asyncSignal\u003cProduct[]\u003e(async () =\u003e {\n  const response = await fetch('https://somedomain.com/your/api/endpoint');\n  return await response.json();\n}, { fallback: [] });\n```\n\n---\n\n## Getting Started\nSimply run:\n    \n    npx plicit-cli myapp \u0026\u0026 cd myapp \u0026\u0026 npm i \u0026\u0026 npm run dev\n    \nNow your app should be up and running!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsebbekarlsson%2Fplicit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsebbekarlsson%2Fplicit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsebbekarlsson%2Fplicit/lists"}