[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-10795":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":16,"forks30d":16,"starsTrendScore":19,"compositeScore":20,"rankGlobal":10,"rankLanguage":10,"license":21,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":24,"hasPages":24,"topics":25,"createdAt":10,"pushedAt":10,"updatedAt":45,"readmeContent":46,"aiSummary":47,"trendingCount":16,"starSnapshotCount":16,"syncStatus":17,"lastSyncTime":48,"discoverSource":49},10795,"omi","Tencent\u002Fomi","Tencent","Web Components Framework - Web组件框架","https:\u002F\u002Fomi.cdn-go.cn\u002F",null,"TypeScript",13257,1257,340,69,0,2,7,1,71,"Other",false,"master",true,[26,27,28,29,30,31,32,5,33,34,35,36,37,38,39,40,41,42,43,44],"components","css","custom-elements","html","javascript","js","jsx","reactive-signal","shadow-dom","signal","signals","tailwind","tailwindcss","ts","tsx","typescript","web","web-components","webcomponents","2026-06-12 04:00:52","English | [简体中文](.\u002FREADME.CN.md) \n\n\u003Cp align=\"center\">\u003Cimg src=\"https:\u002F\u002Fomijs.github.io\u002Fhome\u002Fassets\u002Flogo.svg\" alt=\"omi\" width=\"100\"\u002F>\u003C\u002Fp>\n\u003Ch2 align=\"center\">Omi - Web Components Framework\u003C\u002Fh2>\n\n- 📶 **Signal**-driven reactive programming by [reactive-signal](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Freactive-signal)\n- 🧱 [TDesign Web Components](https:\u002F\u002Fgithub.com\u002FTDesignOteam\u002Ftdesign-web-components) & [OMI Playground](https:\u002F\u002Fomi.cdn-go.cn\u002Ftutorial\u002Flatest\u002F)\n- 💗 [100+ OMI Templates](https:\u002F\u002Fomi.cdn-go.cn\u002Ftemplates\u002Flatest\u002F) & [OMI Templates Source Code](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Fomi-templates)\n- 🐲 [OMI Form](https:\u002F\u002Fomi.cdn-go.cn\u002Fform\u002Flatest\u002Fdocs\u002F) & [OMI Form Playground](https:\u002F\u002Fomi.cdn-go.cn\u002Fform\u002Flatest\u002Fplay\u002F) & [Lucide Omi Icons](https:\u002F\u002Fgithub.com\u002Fomijs\u002Flucide-omi)\n- ⚡ **Tiny** size, **Fast** performance\n- 🌐 Everything you need: **Web Components**, **JSX**, Function Components, Router, Suspense, Directive, Tailwindcss...\n- 💒 Harness **Constructable Stylesheets** to easily manage and share styles\n\n```tsx\nimport { render, signal, tag, Component, h } from 'omi'\n\nconst count = signal(0)\n\nfunction add() {\n  count.value++\n}\n\nfunction sub() {\n  count.value--\n}\n\n@tag('counter-demo')\nexport class CounterDemo extends Component {\n  static css = 'span { color: red; }'\n\n  render() {\n    return (\n      \u003C>\n        \u003Cbutton onClick={sub}>-\u003C\u002Fbutton>\n        \u003Cspan>{count.value}\u003C\u002Fspan>\n        \u003Cbutton onClick={add}>+\u003C\u002Fbutton>\n      \u003C\u002F>\n    )\n  }\n}\n```\n\nUse this component:\n\n```tsx\nimport { h } from 'omi'\nimport '.\u002Fcounter-demo'\n\nrender(\u003Ccounter-demo \u002F>, document.body)\n\n\u002F\u002F or \nimport { CounterDemo, Other } from '.\u002Fcounter-demo'\n\u002F\u002F Prevent tree Shaking when importing other things\nrender(\u003CCounterDemo \u002F>, document.body)\n\n\u002F\u002F or\ndocument.body.appendChild(document.createElement('counter-demo'))\n```\n\n## Install \n\n```bash\nnpm i omi\n```\n\nTo quickly create an Omi + Vite + TS\u002FJS project:\n\n```bash\n$ npx omi-cli init my-app    # or create js project by: npx omi-cli init-js my-app\n$ cd my-app           \n$ npm start           # develop\n$ npm run build       # release\n```\n\nTo quickly create an Omi + **Router** + **Signal** + **Suspense** + **Tailwindcss** + Vite + TS project:\n\n```bash\n$ npx omi-cli init-spa my-app  \n$ cd my-app           \n$ npm start           # develop\n$ npm run build       # release\n```\n\n### Packages\n\n- Core packages\n  - [`omi`](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Fomi) - Implementation of omi framework.\n  - [`omi-form`](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Fomi-form) - Powerful, simple and cross frameworks form solution.\n  - [`lucide-omi`](https:\u002F\u002Fgithub.com\u002Fomijs\u002Flucide-omi) - Lucide icon collection for omi.\n  - [`omiu`](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Fomiu) - Hope to create the best web components. For example, the powerful [vchart](https:\u002F\u002Fvisactor.io\u002Fvchart) and [vtable](https:\u002F\u002Fvisactor.io\u002Fvtable)\n  - [`omi-router`](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Fomi-router) - Create SPA of omi framework.\n  - [`omi-cli`](https:\u002F\u002Fgithub.com\u002Fomijs\u002Fcli) - To quickly create an Omi + Vite + TS\u002FJS project.\n- Starter kits (not published to npm)\n  - [`omi-elements`](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Fomi-elements) - Tailwind Element Omi UI KIT.\n  - [`omi-starter-spa`](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Fomi-starter-spa) - A starter repo for building single page app using Omi + OmiRouter + Tailwindcss + TypeScript + Vite + Prettier.\n  - [`omi-starter-ts`](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Fomi-starter-ts) - A starter repo for building web app or reusable components using Omi in TypeScript base on Vite.\n  - [`omi-starter-tailwind`](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Fomi-starter-tailwind) - A starter repo for building web app or reusable components using Omi + Tailwindcss + TypeScript + Vite.\n  - [`omi-starter-js`](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Fomi-starter-js) - A starter repo for building web app or reusable components using Omi in JavaScript base on Vite.\n  - [`omi-vue`](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Fomi-vue) - Vue SFC + Vite + OMI + OMI-WeUI.\n- Components\n  - [`omi-weui`](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Fomi-weui) - WeUI Components of omi.\n  - [`omi-auto-animate`](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Fomi-auto-animate) - Omi version of @formkit\u002Fauto-animate.\n  - [`omi-suspense`](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Fomi-suspense) - Handling asynchronous dependencies.\n- Directives  \n  - [`omi-transition`](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Fomi-transition) - Applying animations when an component is entering and leaving the DOM.\n  - [`omi-ripple`](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Fomi-ripple) - A lightweight component for adding ripple effects to user interface elements.\n- Examples (not published to npm)\n  - [`snake-game-2tier`](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Fsnake-game-2tier) - SNake Game with `Signal` class\n  - [`snake-game-3tier`](https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Ftree\u002Fmaster\u002Fpackages\u002Fsnake-game-3tier) - SNake Game with reactivity functions\n  - [`omi-tutorial`](https:\u002F\u002Fgithub.com\u002Fomijs\u002Ftutorial) - Source code of omi tutorial.\n\n\n**If you want to help the project grow, start by simply sharing it with your peers!**\n\n- [Share via Dev.to](\u003Chttps:\u002F\u002Fdev.to\u002Fnew?prefill=---%0Atitle%3A%20Omi%20-%20Web%20Components%20Framework%0A---- %20Home%3A%20%5Bomijs.org%5D(http%3A%2F%2Fomijs.org%2F)%20Github%3A%5Bhttps%3A%2F%2Fgithub.com%2FTencent%2Fomi%5D(https%3A%2F%2Fgithub.com%2FTencent%2Fomi)%0A-%20%F0%9F%93%B6%20**Signal**-driven%20reactive%20programming%0A-%20%F0%9F%8E%89%20%5BTailwind%20Element%20Omi%20UI%20KIT%5D(https%3A%2F%2Fomi.cdn-go.cn%2Felements%2Flatest%2F)%0A-%20%E2%9A%A1%20**Tiny**%20size%2C%20**Fast**%20performance%0A-%20%F0%9F%8C%90%20Everything%20you%20need%3A%20**Web%20Components**%2C%20**JSX**%2C%20Router%2C%20Suspense%2C%20Directive%2C%20Tailwindcss...%0A-%20%F0%9F%92%AF%20Both%20**object**%20oriented%20programming(OOP)%20and%20**data**%20oriented%20programming(DOP)%20are%20supported%0A-%20%F0%9F%92%92%20Harness%20**Constructable%20Stylesheets**%20to%20easily%20manage%20and%20share%20styles>)\n- [Share via Twitter](https:\u002F\u002Ftwitter.com\u002Fintent\u002Ftweet?text=Web%20Components%20Framework%20%F0%9F%8E%89http%3A%2F%2Fomijs.org%2F%0A%0A%20Everything%20you%20need%3A%20Web%20Components%2C%20JSX%2C%20Router%2C%20Suspense%2C%20Directive%2C%20Tailwindcss...%20%0A%0A%20Tailwind%20Element%20Omi%20UI%20KIT%3E%20%F0%9F%92%AFhttps%3A%2F%2Fomi.cdn-go.cn%2Felements%2Flatest%2F)\n- [Share via Facebook](https:\u002F\u002Fwww.facebook.com\u002Fsharer\u002Fsharer.php?u=http%3A\u002F\u002Fomijs.org)\n- [Share via LinkedIn](http:\u002F\u002Fwww.linkedin.com\u002FshareArticle?url=http%3A%2F%2Fomijs.org%2F)\n- [Share via Pinterest](https:\u002F\u002Fwww.pinterest.com\u002Fpin\u002Fcreate\u002Fbutton?url=http:\u002F\u002Fomijs.org\u002F&media=https:\u002F\u002Frepository-images.githubusercontent.com\u002F36606437\u002F66abfcfb-096b-4c9d-a290-77165213e605&description=Omi-Web%20Componnets%20Framework)\n- [Share via Reddit](https:\u002F\u002Freddit.com\u002Fsubmit?url=http:\u002F\u002Fomijs.org\u002F&title=web%20components%20framework)\n- [Share via StumbleUpon](https:\u002F\u002Fwww.stumbleupon.com\u002Fsubmit?url=http:\u002F\u002Fomijs.org\u002F&title=web%20components%20framework)\n- [Share via Vkontakte](https:\u002F\u002Fvk.com\u002Fshare.php?url=http:\u002F\u002Fomijs.org\u002F)\n- [Share via Weibo](https:\u002F\u002Fservice.weibo.com\u002Fshare\u002Fshare.php?url=https:\u002F\u002Fomijs.org\u002F&title=web%20components%20framework)\n- [Share via Hackernews](https:\u002F\u002Fnews.ycombinator.com\u002Fsubmitlink?u=http:\u002F\u002Fomijs.org\u002F&t=web%20components%20framework)\n\nThank you!\n\n\n## Usage\n\n### TodoApp with reactivity functions\n\n> Data oriented programming \n\nIn data-oriented programming, the focus is on the data itself and the operations on the data, rather than the objects or data structures that hold the data. This programming paradigm emphasizes the change and flow of data, and how to respond to these changes. The TodoApp with reactivity functions is a good example of this, using the concepts of reactive programming, where the UI automatically updates to reflect changes in the data (i.e., the to-do list).\n\n\n```tsx\nimport { render, signal, computed, tag, Component, h } from 'omi'\n\nconst todos = signal([\n  { text: 'Learn OMI', completed: true },\n  { text: 'Learn Web Components', completed: false },\n  { text: 'Learn JSX', completed: false },\n  { text: 'Learn Signal', completed: false }\n])\n\nconst completedCount = computed(() => {\n  return todos.value.filter(todo => todo.completed).length\n})\n\nconst newItem = signal('')\n\nfunction addTodo() {\n  \u002F\u002F api a\n  todos.value.push({ text: newItem.value, completed: false })\n  todos.update() \u002F\u002F Trigger UI auto update\n  \n  \u002F\u002F api b, same as api a\n  \u002F\u002F todos.value = [...todos.value, { text: newItem.value, completed: false }]\n\n  newItem.value = '' \u002F\u002F Changing the value type can automatically update the UI\n}\n\nfunction removeTodo(index: number) {\n  todos.value.splice(index, 1)\n  todos.update() \u002F\u002F Trigger UI auto update\n}\n\n@tag('todo-list')\nclass TodoList extends Component {\n  onInput = (event: Event) => {\n    const target = event.target as HTMLInputElement\n    newItem.value = target.value\n  }\n\n  render() {\n    return (\n      \u003C>\n        \u003Cinput type=\"text\" value={newItem.value} onInput={this.onInput} \u002F>\n        \u003Cbutton onClick={addTodo}>Add\u003C\u002Fbutton>\n        \u003Cul>\n          {todos.value.map((todo, index) => {\n            return (\n              \u003Cli>\n                \u003Clabel>\n                  \u003Cinput\n                    type=\"checkbox\"\n                    checked={todo.completed}\n                    onInput={() => {\n                      todo.completed = !todo.completed\n                      todos.update() \u002F\u002F Trigger UI auto update\n                    }}\n                  \u002F>\n                  {todo.completed ? \u003Cs>{todo.text}\u003C\u002Fs> : todo.text}\n                \u003C\u002Flabel>\n                {' '}\n                \u003Cbutton onClick={() => removeTodo(index)}>❌\u003C\u002Fbutton>\n              \u003C\u002Fli>\n            )\n          })}\n        \u003C\u002Ful>\n        \u003Cp>Completed count: {completedCount.value}\u003C\u002Fp>\n      \u003C\u002F>\n    )\n  }\n}\n\nrender(\u003Ctodo-list \u002F>, document.body)\n```\n\n## Auto Import h\n\nvite.config.js:\n\n```tsx\nimport { defineConfig } from 'vite'\n\nexport default defineConfig({\n  esbuild: {\n    jsxInject: \"import { h } from 'omi'\",\n    jsxFactory: \"h\",\n    jsxFragment: \"h.f\"\n  }\n})\n```\n\nYou can inject code during construction, so you don't have to manually export `h`.\n\n\u003C!-- ## With Twind\n\n```tsx\nimport { Component, define, h } from 'omi'\n\nimport install from '@twind\u002Fwith-web-components'\nimport { defineConfig } from '@twind\u002Fcore'\nimport presetAutoprefix from '@twind\u002Fpreset-autoprefix'\nimport presetTailwind from '@twind\u002Fpreset-tailwind'\nconst withTwind = install(defineConfig({\n  presets: [presetAutoprefix(), presetTailwind()],\n}))\n\ndefine('my-app', class extends withTwind(Component) {\n  render() {\n    return \u003Ch1 class=\"text-3xl font-bold underline\">Hello world!\u003C\u002Fh1>\n  }\n})\n``` -->\n\n## Define Cross Framework Component\n\nThe case of using Omi component in Vue is as follows:\n\n![](.\u002Fassets\u002Fomi-vue.gif)\n\nmy-counter.tsx:\n\n```tsx\nimport { tag, Component, h, bind } from 'omi'\n\n@tag('my-counter')\nclass MyCounter extends Component {\n  static props = {\n    count: {\n      type: Number,\n      default: 0,\n      changed(newValue, oldValue) {\n        this.state.count = newValue\n        this.update()\n      }\n    }\n  }\n\n  state = {\n    count: null\n  }\n\n  install() {\n    this.state.count = this.props.count\n  }\n\n  @bind\n  sub() {\n    this.state.count--\n    this.update()\n    this.fire('change', this.state.count)\n  }\n\n  @bind\n  add() {\n    this.state.count++\n    this.update()\n    this.fire('change', this.state.count)\n  }\n\n  render() {\n    return (\n      \u003C>\n        \u003Cbutton onClick={this.sub}>-\u003C\u002Fbutton>\n        \u003Cspan>{this.state.count}\u003C\u002Fspan>\n        \u003Cbutton onClick={this.add}>+\u003C\u002Fbutton>\n      \u003C\u002F>\n    )\n  }\n}\n```\n\n### Using in Vue3\n\n```vue\n\u003Cscript setup>\nimport { ref } from 'vue'\n\u002F\u002F import omi component\nimport '.\u002Fmy-counter'\n\ndefineProps({\n  msg: String,\n})\n\nconst count = ref(0)\n\nconst change = (e) => {\n  count.value = e.detail\n}\n\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Ch1>{{ msg }}\u003C\u002Fh1>\n\n  \u003Cmy-counter @change=\"change\" :count=\"count\" \u002F>\n  \u003Cp>\n    【Omi】 \n  \u003C\u002Fp>\n\n  \u003Cdiv class=\"card\">\n    \u003Cbutton type=\"button\" @click=\"count++\">count is {{ count }}\u003C\u002Fbutton>\n    \u003Cp>\n     【Vue】 \n    \u003C\u002Fp>\n  \u003C\u002Fdiv>\n\n\u003C\u002Ftemplate>\n```\n\nIf you `fire` the `count-change` in an Omi component:\n\n```ts\nthis.fire('count-change', this.state.count)\n```\n\nTo use the component and listen for events in Vue:\n\n```html\n\u003Cmy-counter @count-change=\"change\" :count=\"count\" \u002F>\n```\n\n### Using in React\n\n```tsx\nimport { useState, useRef, useEffect } from 'react'\nimport useEventListener from '@use-it\u002Fevent-listener'\nimport '.\u002Fmy-counter'\n\nfunction App() {\n  const [count, setCount] = useState(100)\n  const myCounterRef = useRef(null)\n\n  useEffect(() => {\n    const counter = myCounterRef.current\n    if (counter) {\n      const handleChange = (evt) => {\n        setCount(evt.detail)\n      }\n      counter.addEventListener('change', handleChange)\n      return () => {\n        counter.removeEventListener('change', handleChange)\n      }\n    }\n  }, [])\n\n  return (\n    \u003C>\n      \u003Ch1>Omi + React\u003C\u002Fh1>\n      \u003Cmy-counter count={count} ref={myCounterRef}>\u003C\u002Fmy-counter>\n      \u003Cdiv className=\"card\">\n        \u003Cbutton onClick={() => setCount((count) => count + 1)}>\n          count is {count}\n        \u003C\u002Fbutton>\n      \u003C\u002Fdiv>\n    \u003C\u002F>\n  )\n}\n\nexport default App\n```\n\n## Contributors\n\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FTencent\u002Fomi\u002Fgraphs\u002Fcontributors\">\n  \u003Cimg src=\".\u002Fassets\u002Fcontributors.png\" \u002F>\n\u003C\u002Fa>\n\n## License\n\nMIT © Tencent\n\n\n  \u003C!-- - [`tdesign-omi`](https:\u002F\u002Fgithub.com\u002Fomijs\u002Ftdesign) - `[in progress...]`Cross framework components based on tdesign. [Preview](https:\u002F\u002Fomijs.github.io\u002Ftdesign\u002F) -->","Omi 是一个基于 Web Components 的前端框架，用于构建高效且响应式的用户界面。它采用信号驱动的响应式编程模型，支持 JSX、函数组件、路由、Suspense 等现代前端开发特性，并且集成了 TailwindCSS 以简化样式管理。Omi 框架体积小巧，性能卓越，特别适合需要快速加载和高交互性的Web应用。此外，Omi 还提供了丰富的模板库和表单解决方案，进一步加速了开发流程。无论是创建简单的页面还是复杂的单页应用程序，Omi 都能提供强大的支持。","2026-06-11 03:30:11","top_topic"]