modem
modem: a device that converts signals produced by one type of device (such as a computer) to a form compatible with another (such as a telephone) – Merriam-Webster
Modem is a little library for Lustre that helps you manage navigation and URLs in the browser. It converts url requests into messages that you can handle in your app’s update function. Modem isn’t a router, but it can help you build one!
Quickstart
Getting started with modem is easy! Most application’s can get by with pattern matching on a url’s path: no complicated router setup required. Let’s see what that looks like with modem:
gleam add lustre modem
import gleam/result
import gleam/uri.{type Uri}
import lustre
import lustre/attribute
import lustre/element.{type Element}
import lustre/element/html
import lustre/effect.{type Effect}
import modem
pub fn main() {
  let app = lustre.application(init, update, view)
  let assert Ok(_) = lustre.start(app, "#app", Nil)
}
pub type Route {
  Wibble
  Wobble
}
pub fn init(_) -> #(Route, Effect(Msg)) {
  let route =
    modem.initial_uri()
    |> result.map(fn(uri) { uri.path_segments(uri.path) })
    |> fn(path) {
      case path {
        Ok(["wibble"]) -> Wibble
        Ok(["wobble"]) -> Wobble
        _ -> Wibble
      }
    }
  #(route, modem.init(on_url_change))
}
fn on_url_change(uri: Uri) -> Msg {
  case uri.path_segments(uri.path) {
    ["wibble"] -> OnRouteChange(Wibble)
    ["wobble"] -> OnRouteChange(Wobble)
    _ -> OnRouteChange(Wibble)
  }
}
pub type Msg {
  OnRouteChange(Route)
}
fn update(_, msg: Msg) -> #(Route, Effect(Msg)) {
  case msg {
    OnRouteChange(route) -> #(route, effect.none())
  }
}
fn view(route: Route) -> Element(Msg) {
  html.div([], [
    html.nav([], [
      html.a([attribute.href("/wibble")], [element.text("Go to wibble")]),
      html.a([attribute.href("/wobble")], [element.text("Go to wobble")]),
    ]),
    case route {
      Wibble -> html.h1([], [element.text("You're on wibble")])
      Wobble -> html.h1([], [element.text("You're on wobble")])
    },
  ])
}
Here’s a breakdown of what’s happening:
- 
We define a Routetype that represents the page or route we’re currently on.
- 
modem.initis anEffectthat intercepts clicks to local links and browser back/forward navigation and lets you handle them.
- 
on_url_changeis a function we write that takes an incomingUriand converts it to our app’sMsgtype.
- 
In our viewwe can just use normalhtml.a.elements: no special link component necessary. Pattern matching on theRoutetype lets us render different content for each page.