Skip to main content

Elmish Land

Build reliable, type-safe web applications with the power of F# and the Elm Architecture.

Build pages with the Elm Architecture

Each page is a self-contained module with its own model, update, and view functions. Simple, predictable, and easy to reason about.

src/Pages/Page.fs
type Model = { Count: int }

type Msg =
| Increment
| Decrement

let init () =
{ Count = 0 }, Command.none

let update msg model =
match msg with
| Increment -> { model with Count = model.Count + 1 }, Command.none
| Decrement -> { model with Count = model.Count - 1 }, Command.none

let view model dispatch =
Html.div [
Html.button [ prop.onClick (fun _ -> dispatch Decrement); prop.text "-" ]
Html.span [ prop.text (string model.Count) ]
Html.button [ prop.onClick (fun _ -> dispatch Increment); prop.text "+" ]
]
localhost:5173
0

Route pages with the file system

Just create files in the Pages directory and Elmish Land automatically generates routes. No manual route configuration needed.

Project Structure
📂src/Pages/
📄Page.fs
→/
📂About/
📄Page.fs
→/about
📂Blog/
📂Post/_Slug/
📄Page.fs
→/blog/:slug

Type-safe from URL to page

Define your route parameters in a simple JSON file and get fully typed, parsed route objects in your page functions. No string parsing, no runtime errors.

src/Pages/Blog/route.json
{
"queryParameters": [
{
"type": "int",
"name": "page"
}
]
}
src/Pages/Blog/Page.fs
// Route parameters are parsed and typed automatically
let page (shared: SharedModel) (route: BlogRoute) =
// route.Page : int option (query parameter)
Page.from init update view () LayoutMsg
Type-Safe Routes
🔒myapp.com/blog?page=2
Parsed Route
page : int option = Some 2