https://axii.dev | English | 中文
Axii /ˈæksɪ:/ is a brand-new frontend framework that relies on an "incremental update" reactive data structure to truly build a high-performance data logic layer. 🚀 The official infrastructure provided makes it convenient whether you are creating a component library or developing an application.
-
Simple Mental Model
- Uses React-style JSX, but functions execute only once, creating real DOM elements instead of Virtual DOM.
- Binds updates to elements by recognizing reactive data structures. No special syntax, no framework-specific hooks, no compiler magic.
-
Superior Performance
- Precisely updates DOM nodes and attributes. Component functions never re-execute.
- Reactive data automatically performs incremental computations, resulting in theoretically minimal changes. Significantly reduces computational overhead, especially during complex operations on arrays or collections.
- Rich reactive structures like
RxList/RxMap/RxSet/RxTimesuitable for various scenarios.
-
Powerful Abstraction Tools
- Reactive wrappers for DOM position, size, scroll, and other states commonly used in complex interactions.
- Component AOP mechanism greatly reduces the workload of maintaining reusable components while providing extremely flexible capabilities.
- Style-logic separation implemented through Component AOP can maintain logical integrity outside component function scope. Styles with logical capabilities can be quickly generated from design tools like Figma.
-
Infrastructure Ready for Large Applications
- Official routing system, data request management system, and even a full-featured state machine system.
- Official headless component system, and interesting theme system.
Use the following command to create a new project. It comes with sample code to help you get started quickly:
npx create-axii-app myapp
cd myapp
npm run devBelow is a simple example showing how to use reactive atomic data and bind it to a DOM property:
/* @jsx createElement */
import { createRoot, atom } from 'axii'
function App({}, {createElement}) {
const title = atom('Hello, Reactive World!')
return (
<div>
<input
value={title}
onInput={(e) => title(e.target.value)}
/>
<h1>{() => title()}</h1>
</div>
)
}
const root = document.getElementById('root')
createRoot(root).render(<App />)Here, title is a mutable atomic data. Any assignment to title will automatically update the parts that depend on it, with no manual coordination required.
If you need frequent operations on lists or structures like Map/Set, you can also use the built-in RxList, RxMap, RxSet, which offer superior performance:
/* @jsx createElement */
import { createRoot, RxList } from 'axii'
function ListApp({}, {createElement}) {
const items = new RxList([ 'Apple', 'Banana', 'Cherry' ])
function addItem() {
items.push(`Random-${Math.random().toFixed(2)}`)
}
return (
<div>
<ul>
{items.map(item => <li>{item}</li>)}
</ul>
<button onClick={addItem}>Add Random</button>
</div>
)
}
createRoot(document.getElementById('root')).render(<ListApp />)Whenever the items list changes, that change will be mapped to the DOM incrementally without triggering a complete re-render of the list. 🍀
Check out https://axii.dev for detailed documentation in both Chinese and English, covering:
- Basic concepts: from using
atomtoRxList/RxMap/RxSetwith examples - Principles of reactivity and dynamic DOM rendering
- Component encapsulation, inter-component data passing, and the component AOP mechanism
- Side-effect and destruction logic (
useEffect,useLayoutEffect,ManualCleanup, etc.) - Server-side rendering:
renderToString/hydrateRoot, Portal and lazy contracts - How to effectively apply these features in real-world projects
We provide progressively organized examples and explanations in the documentation, which we believe will help you better understand and utilize the unique ideas of this framework.
axii can string-render on the server and activate the same DOM in the browser without a Virtual DOM pass.
| API | Package | Role |
|---|---|---|
renderToString(source) |
axii/ssr |
Node-safe HTML serialization — no DOM globals |
hydrateRoot(container, source, options?) |
axii |
Claim existing nodes; bind events and reactive hosts |
/* @jsx createElement */
// server (Node)
import { createElement, atom } from 'axii'
import { renderToString } from 'axii/ssr'
function App() {
const title = atom('Hello')
return <h1>{title}</h1>
}
const { html, styles, portals } = renderToString(<App />)
// html ends with <!--root-->. Put `styles` in <style data-axii-ssr>.
// Write portals[key].html into the matching container before hydrate./* @jsx createElement */
// browser
import { createElement, hydrateRoot, atom } from 'axii'
function App() {
const title = atom('Hello')
return <h1>{title}</h1>
}
const root = document.getElementById('root')
root.innerHTML = /* server html */
hydrateRoot(root, <App />)
// Matched nodes keep identity; later updates use the same paths as createRoot().render().Contracts (short):
- Keep the component tree and reactive data identical between
renderToStringandhydrateRoot. axii does not dehydrate application state. - Portal under SSR: use
containerasstring | { id }(orportalKey). Content is inportals[key]; pass filled elements viahydrateRoot(..., { portals }). - lazy: the server always emits the fallback (or
null) and does not awaitload(); the client starts loading after hydrate. - Not in scope: streaming (
renderToStream), app-state serialization. - Design detail and host/marker contracts:
docs/ssr-support/.
- Event handlers are bound once and are not reactive. An
on*prop is attached withaddEventListenerwhen the element is created; passing an atom or a function-returning-handler will not make the binding itself reactive. If you need conditional behavior, write the condition inside the handler (e.g.onClick={(e) => enabled() && doSomething(e)}) instead of trying to swap the handler dynamically.
We welcome you to submit Issues or Pull Requests on GitHub to help polish this new incremental reactive frontend framework. Your ideas and suggestions are extremely important to us!
This project is licensed under the MIT License. You are free to fork and develop upon it, and we look forward to your creative input and feedback!