fiboui
v2.6.0
Published
Flutter/SwiftUI-inspired React UI — fluent builders, signals, and themes. https://fiboui.vercel.app
Maintainers
Readme
FiboUI
Fluent React UI. Flutter & SwiftUI energy for the web.
There is no JSX — the function return is the view.
Live product
| Marketing site | Store demo |
| :---: | :---: |
|
|
|
| fiboui.vercel.app | fiboui-store.vercel.app |
Both ships are built only with FiboUI fluent builders — no JSX in the product UI.
Cursor / VS Code extension
Fluent trees get Flutter-style closing labels (// Column, // List, // Form), auto-indent on Enter, lineage guides on .children([…]), snippets (fcol, frow, …), chain autocomplete, and the FiboUI Noir colour theme.
ln -sfn "$(pwd)/extensions/vscode-fiboui" \
"$HOME/.cursor/extensions/felipeoliveiradev.fiboui-0.1.0"Reload the window, then pick theme FiboUI Noir. Details: extensions/vscode-fiboui/README.md.
Install
npm install fibouiimport 'fiboui/style.css' // required once — JS does not load CSS
import { Button, Column, Text, mount } from 'fiboui'
function App() {
return Column()
.gap(12)
.padding(24)
.children([
Text('Hello FiboUI').variant('h1'),
Button('Ship it').onPress(() => undefined),
])
}
mount('#root', App)ESM-only · React 18 / 19 · Next App Router → 'use client' on files that call builders.
JSX vs FiboUI
// ── JSX ──────────────────────────────────
<div className="flex flex-col gap-3 p-6">
<h1>Hello</h1>
<button onClick={onShip}>Ship it</button>
</div>
// ── FiboUI ───────────────────────────────
Column()
.gap(12)
.padding(24)
.children([
Text('Hello').variant('h1'),
Button('Ship it').onPress(onShip),
])Same tree. Method calls instead of tags. Layout, theme, motion, and reactivity stay on the builder.
Runtime flow
flowchart LR
A["Column()"] --> B[".gap().padding()"]
B --> C[".children([...])"]
C --> D["React element"]
D --> E["mount / return"]
style A fill:#141414,stroke:#fff,color:#fff
style B fill:#141414,stroke:#ff2d8a,color:#ff2d8a
style C fill:#141414,stroke:#c8ff00,color:#c8ff00
style D fill:#141414,stroke:#fff,color:#fff
style E fill:#c8ff00,stroke:#c8ff00,color:#0a0a0aBuilders are valid React elements (isValidElement(Button('Go'))).
Return them. Nest them. Skip .build().
Signal flow
import { Box, Button, Text, signal } from 'fiboui'
const count = signal(0)
Box()
.bindSignal(count)
.children(() => [
Text(`Count: ${count.value}`),
Button('+').onPress(() => {
count.value += 1
}),
]).bindSignal re-assembles. Read .value inside a function child so updates are live. Text(`Total ${todos.$length}`) stays live without a function child. Forms and validation: Form.
sequenceDiagram
participant UI as Builder tree
participant S as signal(count)
participant H as onPress
UI->>S: .bindSignal(count)
H->>S: count.value += 1
S-->>UI: notify subscribers
UI->>UI: re-assemble children()Package architecture
flowchart TB
APP["your app — screens · domain · mount"]
subgraph builders["fluent builders"]
L["layout / content<br/>Column · Row · Text · Button"]
S["structure / nav<br/>Box · Grid · Scaffold"]
T["theme / motion<br/>noir · animate · hover"]
R["reactivity<br/>signal · computed · store"]
end
CORE["core — FiboBuilder · styleManager · bindSignal"]
APP --> L & S & T & R
L & S & T & R --> CORE
style APP fill:#141414,stroke:#c8ff00,color:#c8ff00
style CORE fill:#c8ff00,stroke:#c8ff00,color:#0a0a0a
style L fill:#141414,stroke:#ff2d8a,color:#ff2d8a
style S fill:#141414,stroke:#fff,color:#fff
style T fill:#141414,stroke:#fff,color:#fff
style R fill:#141414,stroke:#fff,color:#fffWhy FiboUI
| | |
| :--- | :--- |
| Assembly pattern | Factories return builders for endless chaining |
| Zero-build children | Pass builders to .children() — they finalize implicitly |
| Signals | signal(), computed(), .bindSignal(), .observer() |
| Themes | .theme("noir") · extendTheme · Material / Cupertino / Web / Noir |
| Motion | .animate('fadeIn') · .onScroll · .hoverEffect · CSS-first |
| Type-safe | TypeScript builders · FiboChild / FiboChildren |
Themes & motion
Box()
.theme('noir')
.animate('fadeIn')
.ease('spring')
.hover((h) => h.effect('sweepToRight'))
Box().padding(8).md({ padding: 16 }).lg({ padding: 24 })Layout notes
FiboUI 2.x matches Flutter / SwiftUI: Column defaults to crossAxisAlignment('center').Row uses align-self: stretch so spaceBetween still fills width.
Column().crossAxisAlignment('stretch')Button uses .onPress (not onClick).
Brand
| Token | Hex | |
| :---: | :---: | :--- |
| Ink | #0a0a0a | background |
| Chalk | #ffffff | type |
| Pink | #ff2d8a | energy |
| Lime | #c8ff00 | mark / CTA |
Tailored to each request · Attention to detail
Docs & contributing
| | |
| :--- | :--- |
| Migration from 1.x | MIGRATION.md |
| Contributing & release | CONTRIBUTING.md |
| Animation guide | docs/guide/animation.md |
| Brand assets | docs/brand/ |
Publishing is automated on main (GitHub Actions + NPM_TOKEN). Prefer not to npm publish locally.
Wear the return.
MIT © 2025–2026 FiboUI
