elm-spa

Routing

With elm-spa, the names of pages in the src/Pages folder automatically generate your routes! Check out the following examples to learn more.

Static Routes

You can create a static route like /contact or /not-found by creating an elm file in src/Pages:

File URL
People.elm /people
About/Careers.elm /about/careers
OurTeam.elm /our-team

Capitalization matters! Notice how OurTeam became our-team? Capital letters within file names are translated to dashes in URLs.

Top Level Routes

Routes like the homepage use the reserved Top keyword to indicate that a page should not be a static route.

File URL
Top.elm /
Example/Top.elm /example
Top/Top.elm /top

Reserved, but possible! If you actually need a /top route, you can still make one by using Top.elm within a Top folder. (As shown above!)

Dynamic Routes

Sometimes it's nice to have one page that works for slightly different URLs. elm-spa uses this convention in file names to indicate a dynamic route:

Authors/Name_String.elm

URL Params
/authors/ryan { name = "ryan" }
/authors/alexa { name = "alexa" }

Posts/Id_Int.elm

URL Params
/posts/123 { id = 123 }
/posts/456 { id = 456 }

You can access these dynamic parameters from the Url Params value passed into each page type!

Supported Parameters: Only String and Int dynamic parameters are supported.

Nested Dynamic Routes

You can also nest your dynamic routes. Here's an example:

Users/User_String/Posts/Id_Int.elm

URL Params
/users/ryan/posts/123 { user = "ryan"
, id = 123
}
/users/alexa/posts/456 { user = "alexa"
, id = 456
}

URL Params

As we'll see in the next section, every page will get access to Url Params– these allow you access a few things:

type alias Url params =
  { params : params
  , query : Dict String String
  , key : Browser.Navigation.Key
  , rawUrl : Url.Url
  }

params

Each dynamic page has its own params, pulled from the URL. There are examples in the "Params" column above.

type alias Params =
  { name : String
  }

view : Url Params -> Document Msg
view url =
  { title = "Author: " ++ url.params.name
  , body = -- ...
  }

query

A dictionary of query parameters. Here are some examples:

-- https://elm-spa.dev
Dict.get "name" url.query == Nothing

-- https://elm-spa.dev?name=ryan
Dict.get "name" url.query == Just "ryan"

-- https://elm-spa.dev?name
Dict.get "name" url.query == Just ""

key

Required for programmatic navigation with Nav.pushUrl and other functions from elm/browser

rawUrl

The original URL in case you need any other information like the protocol, port, etc.

Programmatic Navigation

The elm/browser package allows us to programmatically navigate to another page, if we provide a Browser.Navigation.Key. Fortunately, the Url params record above contains that key, and is available on all pages (and the Shared module)!

I recommend creating a common module, like Utils.Route that you can use in your application:

module Utils.Route exposing (navigate)

import Browser.Navigation as Nav
import Spa.Generated.Route as Route exposing (Route)


navigate : Nav.Key -> Route -> Cmd msg
navigate key route =
  Nav.pushUrl key (Route.toString route)

From there, you can call Utils.Route.navigate from any init or update function with your desired route.

module Pages.Dashboard exposing (..)

import Utils.Route

-- ...

init : Url Params -> ( Model, Cmd Msg )
init url =
  ( Model { ... }
  , Utils.Route.navigate url.key Route.SignIn
  )

Let's take a closer look at Pages!