Foldkit
⚠️ Experimental: This is a canary release for early adopters and experimenters. APIs may change rapidly.
An Elm-inspired UI framework powered by Effect-TS, bringing functional programming patterns to the web.
Installation
npm install @foldkit/core effect
Quick Start
import { Effect, Schema } from 'effect'
import { Fold, Runtime } from '@foldkit/core'
import { Class, Html, OnClick, button, div } from '@foldkit/html'
import { ST, ts } from '@foldkit/schema'
const Model = Schema.Number
type Model = ST<typeof Model>
const Decrement = ts('Decrement')
const Increment = ts('Increment')
const Reset = ts('Reset')
const Message = Schema.Union(Decrement, Increment, Reset)
type Decrement = ST<typeof Decrement>
type Increment = ST<typeof Increment>
type Reset = ST<typeof Reset>
type Message = ST<typeof Message>
const update = Fold.fold<Model, Message>({
Decrement: (count) => [count - 1, []],
Increment: (count) => [count + 1, []],
Reset: () => [0, []],
})
const init: Runtime.ElementInit<Model, Message> = () => [0, []]
const view = (count: Model): Html =>
div(
[Class('min-h-screen bg-white flex flex-col items-center justify-center gap-6 p-6')],
[
div([Class('text-6xl font-bold text-gray-800')], [count.toString()]),
div(
[Class('flex flex-wrap justify-center gap-4')],
[
button([OnClick(Decrement.make()), Class(buttonStyle)], ['-']),
button([OnClick(Reset.make()), Class(buttonStyle)], ['Reset']),
button([OnClick(Increment.make()), Class(buttonStyle)], ['+']),
],
),
],
)
const buttonStyle = 'bg-black text-white hover:bg-gray-700 px-4 py-2 transition'
const element = Runtime.makeElement({
Model,
init,
update,
view,
container: document.getElementById('root')!,
})
Effect.runFork(element)
Core Concepts
- Model: Your application state (Schema)
- Messages: Tagged unions representing events
- Update: Fold patterns that transform model and return effects
- View: Functions that render model to virtual DOM
📚 Full documentation and examples: https://github.com/devinjameson/foldkit