Navigating between sections of a single page app (website)

I’ve been struggling to create a simple single page website (app) in elm. I’ve had people try to help on the slack channel but it’s not benefited me much so I thought I’ll ask here hoping for more helpful pointers and guidance.

So I need a single html document say index.html with four navigation menus Home, About, Services and Contact. The page will have 4 HTML sections one for each menu item. When I select a menu option, I expect to be taken to that section of the document (page). Also if I scroll the document instead, I expect the corresponding menu option to be highlighted in some way (say underline) to match the section of the scroll position.

With these requirements I used the example app from the Elm guide - Web Apps - section. I then changed the View to this:

view : Model -> Browser.Document Msg
view model =
  { title = "URL Interceptor"
  , body =
      [ text "The current URL is: "
      , b [] [ text (Url.toString model.url) ]
      , ul []
          [ viewLink "#home"
          , viewLink "#about"
          , viewLink "#services"
          , viewLink "#contactus"
          ]
      ]
        , div [ id "home"]
            [ p [] [ text "\n Section Text"]]
        , div [ id "about"]
            [ p [] [ text "\n Section Text"]]
        , div [ id "services"]
            [ p [] [ text "\n Section Text"]]
        , div [ id "contactus"]
            [ p [] [ text "\n Section Text"]]
  }

My understanding so far is, I have to use a parser, in this case a fragment parser like this:

type alias Docs =
  (String, Maybe String)

docsParser : Parser (Docs -> a) a
docsParser =
 map Tuple.pair (string </> fragment identity)

From here what I think I need to do, is us a Case expression in the view to render the particular section that has an id matching the docsParser.

If I’m right so far what will such a code look like? On the other hand what am I not getting and how do I implement this?

As for the menu option changing the match the scroll position in the document, I’ve not gotten there yet so I don’t have any implementation steps for that yet.

Thanks

For the navigation, if I understand correctly, you only have one page, so you can let the browser do its job with fragments, no need to handle navigation and scrolling yourself:

https://ellie-app.com/4cYct6jfjJya1

Then to highlight the current section (and/or its link), you will have to subscribe to some event, maybe a timer, maybe onAnimationFrame or maybe a scroll event (this last one may require a small port to do it on the document), then use Browser.Dom.getElement on each section to decide which one is the new current section of the Model (not that simple as several ones may be displayed at once, so the last one might never be highlighted if the page ends just after it).

At last you can style the model current section in the view differently (and/or its link).

Note that you may want to debounce the event to avoid updating too much.

Without debouncing and with a scroll event through a port, you could get something like https://ellie-app.com/4cZdJ7VkjBpa1.
And as you can see, it may not be possible to highlight the last section(s) if your window is high enough, including when clicking the link. This is a downside of these kinds of current section detection, to which you could find various workarounds, more or less hacky.

1 Like

Thanks so much! It’s exactly what I was looking for. I’m most grateful.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.