flexium
v0.17.2
Published
A lightweight, signals-based UI framework with cross-platform renderers
Maintainers
Readme
Flexium
Simpler, Faster, Unified.
Flexium is a next-generation UI framework that unifies state management, async data fetching, and global state into a single, powerful API: use().
Key Features
- Unified State API - No more
useRecoil,useQueryseparation. Justuse(). - No Virtual DOM - Direct DOM updates via Proxy-based fine-grained reactivity.
- Tiny Bundle - Minimal footprint with tree-shaking support.
- Cross-Platform - DOM and Server (SSR) renderers included.
- TypeScript First - Full type inference out of the box.
- Zero-Config JSX - Works with standard tooling.
Installation
npm install flexiumQuick Start
npm create flexium@latest my-app
cd my-app
npm install
npm run devThe Only API You Need: use()
Flexium unifies all state concepts into one function.
Local State
import { use } from 'flexium/core'
import { render } from 'flexium/dom'
function Counter() {
const [count, setCount] = use(0)
return (
<button onclick={() => setCount(c => c + 1)}>
Count: {count}
</button>
)
}
render(Counter, document.getElementById('app'))Global State
Just add a key to share state across components. Keys can be strings or arrays.
// Define global state with array key
const [theme, setTheme] = use('light', { key: ['app', 'theme'] })
function ThemeToggle() {
// Access same state anywhere with the same key
const [theme, setTheme] = use('light', { key: ['app', 'theme'] })
return (
<button onclick={() => setTheme(t => t === 'light' ? 'dark' : 'light')}>
Theme: {theme}
</button>
)
}Async Resources
Pass an async function to handle data fetching automatically.
function UserProfile({ id }) {
const [user, control] = use(async () => {
const res = await fetch(`/api/users/${id}`)
return res.json()
})
if (control.loading) return <div>Loading...</div>
if (control.error) return <div>Error!</div>
return (
<div>
<h1>{user.name}</h1>
<button onclick={() => control.refetch()}>Reload</button>
</div>
)
}Computed/Derived State
const [count, setCount] = use(1)
const [doubled] = use(() => count * 2, [count])Package Structure
flexium
├── /core # Core reactivity: use(), sync(), useRef(), Context, Useable
├── /dom # DOM renderer: render(), hydrate(), Portal, Suspense
├── /router # SPA routing: Routes, Route, Link, Outlet, useRouter(), useLocation()
└── /server # SSR: renderToString(), renderToStaticMarkup()Control Flow
Use native JavaScript for control flow - no special components needed:
// Conditional rendering
{isLoggedIn ? <Dashboard /> : <Login />}
// Short-circuit for simple conditions
{isAdmin && <AdminPanel />}
// List rendering
{items.map(item => <Item key={item.id} data={item} />)}Routing
import { Routes, Route, Link, useRouter } from 'flexium/router'
function App() {
return (
<Routes>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Route path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/users/:id" component={UserProfile} />
</Routes>
)
}
function UserProfile({ params }) {
return <h1>User: {params.id}</h1>
}
// Or use the router hook
function UserProfileHook() {
const r = useRouter()
return <h1>User: {r.params.id}</h1>
}Server-Side Rendering
import { renderToString } from 'flexium/server'
import { hydrate } from 'flexium/dom'
// Server
const { html, state } = renderToString(App, { hydrate: true })
// Client
hydrate(App, document.getElementById('root'), { state })Built-in Components
Portal
import { Portal } from 'flexium/dom'
<Portal target={document.body}>
<Modal />
</Portal>Suspense
import { Suspense, lazy } from 'flexium/dom'
const LazyComponent = lazy(() => import('./Heavy'))
<Suspense fallback={<Loading />}>
<LazyComponent />
</Suspense>ErrorBoundary
import { ErrorBoundary } from 'flexium/dom'
<ErrorBoundary fallback={(error) => <Error message={error.message} />}>
<App />
</ErrorBoundary>Context API
import { use, Context } from 'flexium/core'
// Create context with default value
const ThemeCtx = new Context<'light' | 'dark'>('light')
function App() {
const [theme, setTheme] = use<'light' | 'dark'>('light')
return (
<ThemeCtx.Provider value={theme}>
<button onclick={() => setTheme(t => t === 'light' ? 'dark' : 'light')}>
Toggle Theme
</button>
<Child />
</ThemeCtx.Provider>
)
}
function Child() {
const [theme] = use(ThemeCtx)
return <div class={theme}>Current theme: {theme}</div>
}Ecosystem
| Package | Description | |---------|-------------| | flexium-ui | Column/Row based UI component library | | flexium-canvas | Canvas, WebGL, and interactive modules | | create-flexium | Scaffold a Flexium app |
Documentation
Full documentation available at https://flexium.junhyuk.im
License
MIT
