feireact
v1.2.2
Published
A lightweight React-like UI Library
Maintainers
Readme
FeiReact
FeiReact is a lightweight, React-inspired UI library built from first principles by Faye Wang.
It is designed to feel very close to React in everyday use, while staying small and understandable. FeiReact focuses on the core ideas of declarative rendering, functional components, hooks, virtual DOM diffing, context, and simple client-side routing.
It is not trying to match modern React feature-for-feature. However, if you already like React's component model and mental model, FeiReact should feel familiar quickly.
It is also a genuinely working system, not just a toy architecture exercise. I have built my own website with it at faye-wang.vercel.app, and it is powerful enough to build real demos and small apps.
Create a FeiReact app
The recommended way to start is with the official scaffolding tool, create-feireact-app:
npx create-feireact-app my-appThen run:
cd my-app
npm run devThis gives you a ready-to-run Vite app already configured for FeiReact, including the correct JSX runtime setup.
FeiReact Features
- Declarative UI with JSX
- Functional component model
- Virtual DOM rendering, diffing, and reconciliation
- Built-in hooks system:
useState,useEffect,useMemo,useRef, etc. - Context API
- Memoization utilities
- Simple client-side routing
Examples
Counter
State is straightforward and intentionally React-like:
import { render, useState } from "feireact"
function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<p>Count: {count}</p>
<button onclick={() => setCount(prev => prev + 1)}>
Increment
</button>
</div>
)
}
render(<Counter />, document.getElementById("root"))Search with effects and memoization
This example combines useState, useEffect, useMemo, and useRef:
import { useEffect, useMemo, useRef, useState } from "feireact"
function SearchBox({ items }) {
const [query, setQuery] = useState("")
const [status, setStatus] = useState("Ready")
const inputRef = useRef(null)
useEffect(() => {
inputRef.current.focus()
setStatus("Type to filter the list")
}, [])
const filteredItems = useMemo(() => {
return items.filter(item =>
item.toLowerCase().includes(query.toLowerCase())
)
}, [items, query])
return (
<div>
<p>{status}</p>
<input
ref={inputRef}
value={query}
oninput={event => setQuery(event.target.value)}
placeholder="Search"
/>
<ul>
{filteredItems.map(item => <li>{item}</li>)}
</ul>
</div>
)
}Context
Context works well for shared app state:
import { createContext, useContext, useState } from "feireact"
const ThemeContext = createContext({ theme: "light" })
function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light")
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
)
}
function ThemeToggle() {
const { theme, setTheme } = useContext(ThemeContext)
return (
<button onclick={() => setTheme(theme === "light" ? "dark" : "light")}>
Current theme: {theme}
</button>
)
}
function App() {
return (
<ThemeProvider>
<ThemeToggle />
</ThemeProvider>
)
}Router
FeiReact also ships with a small client-side router:
import { Link, Route } from "feireact/router"
function Home() {
return <h1>Home</h1>
}
function About() {
return <h1>About</h1>
}
export default function App() {
return (
<div>
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
</nav>
<Route path="/" component={Home} exact />
<Route path="/about" component={About} exact />
</div>
)
}Package exports
FeiReact currently exposes:
feireactfeireact/routerfeireact/jsx-runtimefeireact/jsx-dev-runtime
Design philosophy
FeiReact intentionally favors:
- conceptual clarity over completeness
- predictable behavior over advanced optimization
- explicit tradeoffs over framework magic
That means some modern framework features are intentionally out of scope.
Current limitations
FeiReact is still a small runtime with deliberate constraints.
Notable limitations include:
- no Fiber or concurrent rendering
- no key-based reconciliation
- no advanced scheduling
- no Suspense or transitions
- context is simple and structural
- some edge cases in renderer behavior are intentionally not heavily abstracted away
For example, the project is happiest when components return elements rather than bare string literals.
FeiReact is powerful enough to build real demos and small apps, but it should still be treated as an experimental runtime rather than a production-grade framework. A good way to think about it is: a fun, complex, and surprisingly capable prototype that captures much of the React feel without pretending to be React itself.
Recommended workflow
The intended developer experience is:
- Scaffold with
create-feireact-app - Build with Vite
- Use the automatic JSX runtime configured for FeiReact
That path gives the smoothest setup and best reflects how FeiReact is meant to be used.
Ecosystem
- FeiReact runtime: this repo
- create-feireact-app: the official scaffolding tool - https://www.npmjs.com/package/create-feireact-app
Contributing
Issues and contributions are welcome.
FeiReact is still evolving, so feedback on API design, examples, and developer experience is especially helpful.
