# Pages In __elm-spa__, every URL connects to a single page. Let's take a closer look at the homepage created with the `elm-spa new` command: ```elm module Pages.Home_ exposing (view) import Html import View exposing (View) view : View msg view = { title = "Homepage" , body = [ Html.text "Hello, world!" ] } ``` This homepage renders __"Homepage"__ in the browser tab, and __"Hello, world!"__ onto the page. Because the file is named `Home_.elm`, elm-spa knows this is the homepage. Visiting `http://localhost:1234` in a web browser will render this view. A `view` function is perfect when all you need is to render some HTML on the screen. But many web pages in the real world do more interesting things! ### Upgrading "Hello, world!" Let's start by adding a new `page` function: ```elm module Pages.Home_ exposing (page) import Html import Page exposing (Page) import Request exposing (Request) import Shared import View exposing (View) page : Shared.Model -> Request -> Page page shared req = Page.static { view = view } view : View msg view = { title = "Homepage" , body = [ Html.text "Hello, world!" ] } ``` We haven't changed the original code much- except we've added a new `page` function that: 1. Accepts 2 inputs: `Shared.Model` and `Request` 2. Returns a `Page` value 3. Has been __exposed__ at the top of the file. > Exposing `page` from this module lets __elm-spa__ know we want to use `page` instead of the plain `view` function from before. The `view` function from before is now passed into `page`. In the web browser, we still see __"Hello, world!"__. However, this page now has access to two new bits of information! 1. `Shared.Model` is our global application state, which might contain the signed-in user, settings, or other things that should persist as we move from one page to another. 2. `Request` is a record with access to the current route, query parameters, and any other information about the current URL. You can rely on the fact that the `page` will always be passed the latest `Shared.Model` and `Request` value. If we want either of these values to be available in our `view` function, we pass them in like so: ```elm page : Shared.Model -> Request -> Page page shared req = Page.static { view = view req -- passing in req here! } ``` Now our `view` function can read the current `URL` value: ```elm view : Request -> View msg view req = { title = "Homepage" , body = [ Html.text ("Hello, " ++ req.url.host ++ "!") ] } ``` Now the browser should display __"Hello, localhost!"__ ### Beyond static pages You might have noticed `Page.static` earlier in our page function. This is one of the built in __page types__ that is built-in to __elm-spa__. The rest of this section will introduce you to the other __page types__ exposed by the `Page` module, so you know which one to reach for. > Always choose the __simplest__ page type for the job– and reach for the more advanced ones when your page _really_ needs the extra features! - __[Page.static](#pagestatic)__ - for pages that only render a view. - __[Page.sandbox](#pagesandbox)__ - for pages that need to keep track of state. - __[Page.element](#pageelement)__ - for pages that send HTTP requests or continually listen for events from the browser or user. - __[Page.advanced](#pageadvanced)__ - for pages that need to sign in a user or work with other details that should persist between page navigation. ## Page.static ```terminal elm-spa add /example static ``` This was the page type we looked at above. It is perfect for pages that render static HTML, but might need access to the `Shared.Model` or `Request` values. ```elm module Pages.Example exposing (page) page : Shared.Model -> Request -> Page page shared req = Page.static { view = view } view : View msg ``` ## Page.sandbox ```terminal elm-spa add /example sandbox ``` This is the first __page type__ that introduces [the Elm architecture](https://guide.elm-lang.org/architecture/), which uses `Model` to store the current page state and `Msg` to define what actions users can take on this page. It's time to upgrade to `Page.sandbox` when you __need to track state__ on the page. Here are a few examples of things you'd store in page state: - The current slide of a carousel - The selected tab section to view - The open / close state of a modal All these examples require us to be able to __initialize__ a `Model`, __update__ it based on `Msg` values sent from the __view__. If you are new to the Elm architecture, be sure to visit [guide.elm-lang.org](https://guide.elm-lang.org/architecture/). We'll be using it for all the upcoming page types! ```elm module Pages.Example exposing (Model, Msg, page) page : Shared.Model -> Request -> Page.With Model Msg page shared req = Page.sandbox { init = init , update = update , view = view } init : Model update : Msg -> Model -> Model view : Model -> View Msg ``` > Our `page` function now returns `Page.With Model Msg` instead of `Page`. This is because our page is now stateful. _( Inspired by [__Browser.sandbox__](https://package.elm-lang.org/packages/elm/browser/latest/Browser#sandbox) )_ ## Page.element ```terminal elm-spa add /example element ``` When you are ready to send __HTTP requests__ or __subscribe to events__ like keyboard presses, mouse move, or incoming data from JS– upgrade to `Page.element`. This is the same as `Page.sandbox`, but introduces `Cmd Msg` and `Sub Msg` to handle side effects. ```elm module Pages.Example exposing (Model, Msg, page) page : Shared.Model -> Request -> Page.With Model Msg page shared req = Page.element { init = init , update = update , view = view , subscriptions = subscriptions } init : ( Model, Cmd Msg ) update : Msg -> Model -> ( Model, Cmd Msg ) view : Model -> View Msg subscriptions : Model -> Sub Msg ``` _( Inspired by [__Browser.element__](https://package.elm-lang.org/packages/elm/browser/latest/Browser#element) )_ ## Page.advanced ```terminal elm-spa add /example advanced ``` For many applications, `Page.element` is all you need to store a `Model`, handle `Msg` values, and work with side-effects. Some Elm users prefer sending global updates directly from their pages, so we've included this `Page.advanced` page type. Using a custom `Effect` module, users are able to send `Cmd Msg` value via `Effect.fromCmd` or `Shared.Msg` values with `Effect.fromSharedMsg`. ```elm module Pages.Example exposing (Model, Msg, page) page : Shared.Model -> Request -> Page.With Model Msg page shared req = Page.advanced { init = init , update = update , view = view , subscriptions = subscriptions } init : ( Model, Effect Msg ) update : Msg -> Model -> ( Model, Effect Msg ) view : Model -> View Msg subscriptions : Model -> Sub Msg ``` This `Effect Msg` value also allows support for folks using [elm-program-test](https://package.elm-lang.org/packages/avh4/elm-program-test/latest/), which requires users to define their own custom type on top of `Cmd Msg`. More about that in the [testing guide](/examples/06-testing) ## Page.protected Each of those four __page types__ also have a __protected__ version. This means pages are guaranteed to receive a `User` or redirect if no user is signed in. ```elm -- not protected Page.sandbox { init : Model , update : Msg -> Model -> Model , view : Model -> View Msg } -- protected Page.protected.sandbox : User -> { init : Model , update : Msg -> Model -> Model , view : Model -> View Msg } ``` When you are ready for user authentication, you can learn more about using `Page.protected` in the [authentication guide](/examples/04-authentication). --- __Next up:__ [Requests](./04-requests)