mpizenberg/elm-url-navigation-port/1.0.0

NOTE: the latest version is 1.1.0

Navigation

Port-based SPA navigation for Browser.element.

This module provides helpers for navigating with ports instead of using Browser.application. Your application defines two ports:

port navCmd : Nav.CommandPort msg


port onNavEvent : Nav.EventPort msg

Then use pushUrl, replaceUrl, and pushState to send navigation commands, and onEvent to subscribe to navigation events.

Use back and forward to traverse history.

Note: The History API only accepts same-origin URLs. All navigation commands produce relative URL strings via AppUrl, which are always same-origin by construction.

Port Types

type alias CommandPort msg =
Value -> Cmd msg

Type alias for an outgoing command port.

Declare this in your port module:

port navCmd : Nav.CommandPort msg
type alias EventPort msg =
(Value -> msg) -> Sub msg

Type alias for an incoming event port.

Declare this in your port module:

port onNavEvent : Nav.EventPort msg

Commands

pushUrl : CommandPort msg -> AppUrl -> Cmd msg

Navigate to a URL, creating a new history entry.

The JS companion calls history.pushState(null, "", url) and notifies Elm of the new location.

update msg model =
    case msg of
        NavigateTo appUrl ->
            ( model, Nav.pushUrl navCmd appUrl )
replaceUrl : CommandPort msg -> AppUrl -> Cmd msg

Replace the current URL without creating a history entry.

The JS companion calls history.replaceState(state, "", url) and does not notify Elm. Use this for cosmetic URL updates where the model is the source of truth.

( { model | counter = n }
, Nav.replaceUrl navCmd
    { path = [ "about" ]
    , queryParameters = Dict.empty
    , fragment = Just (String.fromInt n)
    }
)
pushState : CommandPort msg -> Value -> Cmd msg

Push a state object into the history without changing the URL.

The JS companion calls history.pushState(state, "") and notifies Elm with both the URL and the state. Useful for wizard steps or tab-like flows that should support the back button but don't need distinct URLs.

Nav.pushState navCmd
    (Encode.object [ ( "step", Encode.int 2 ) ])

History Traversal

back : CommandPort msg -> Int -> Cmd msg

Go back by the given number of steps in session history.

Calls history.go(-n). The existing popstate listener handles the resulting navigation event automatically.

Nav.back navCmd 1 -- equivalent to pressing the browser Back button


Nav.back navCmd 2 -- go back two pages
forward : CommandPort msg -> Int -> Cmd msg

Go forward by the given number of steps in session history.

Calls history.go(n). The existing popstate listener handles the resulting navigation event automatically.

Nav.forward navCmd 1 -- equivalent to pressing the browser Forward button


Nav.forward navCmd 2 -- go forward two pages

Events

type alias Event =
{ appUrl : AppUrl
, state : Value
}

Data sent by the JS companion after a navigation event.

  • appUrl — the parsed AppUrl (path, query parameters, fragment)
  • state — the history state object, or null if none was set
decoder : Decoder Event

Decode a navigation event from the JS companion.

Decodes the href field into an AppUrl (failing if the URL is malformed) and preserves the state field as a raw JSON value.

onEvent : EventPort msg -> (Event -> msg) -> Sub msg

Subscribe to navigation events.

subscriptions _ =
    Nav.onEvent onNavEvent GotNavigationEvent