{"id":15285976,"url":"https://github.com/apuchenkin/elm-nested-router","last_synced_at":"2025-06-30T12:33:56.953Z","repository":{"id":57674782,"uuid":"52157361","full_name":"apuchenkin/elm-nested-router","owner":"apuchenkin","description":"A simple nested router for Elm SPA","archived":false,"fork":false,"pushed_at":"2017-10-12T12:49:41.000Z","size":477,"stargazers_count":14,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-20T03:29:58.572Z","etag":null,"topics":["elm","router"],"latest_commit_sha":null,"homepage":null,"language":"Elm","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/apuchenkin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-02-20T14:30:26.000Z","updated_at":"2020-07-04T14:59:32.000Z","dependencies_parsed_at":"2022-09-19T07:31:40.002Z","dependency_job_id":null,"html_url":"https://github.com/apuchenkin/elm-nested-router","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apuchenkin%2Felm-nested-router","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apuchenkin%2Felm-nested-router/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apuchenkin%2Felm-nested-router/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apuchenkin%2Felm-nested-router/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/apuchenkin","download_url":"https://codeload.github.com/apuchenkin/elm-nested-router/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apuchenkin%2Felm-nested-router/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":257601739,"owners_count":22571415,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elm","router"],"created_at":"2024-09-30T15:08:53.448Z","updated_at":"2025-06-30T12:33:56.930Z","avatar_url":"https://github.com/apuchenkin.png","language":"Elm","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Elm nested router [![Build Status](https://travis-ci.org/apuchenkin/elm-nested-router.svg?branch=master)](https://travis-ci.org/apuchenkin/elm-nested-router)\n\nA simple router for single page applications, written in Elm.\n\n**Elm nested router** allows to separate application logic by specific routes.\nFor every `Route` you can provide a list of messages that has to be performed on entering to `Route`, and a `render` function that renders `Route` specific HTML parts.\n\n## Example\n\nTo create a routeable application we have to keep `Router` state (Current route and arguments) in application state.\nIn order to do this we create our application state by using a helper `WithRouter`:\n\n```elm\nimport Router\nimport Router.Types exposing (WithRouter)\n\n-- We use `WithRouter` to define application state\ntype alias State = WithRouter Route\n  {\n    categories: List Category,\n    posts: List Post,\n    post: Maybe Post\n  }\n\n-- construct initialState with initial values\ninitialState : State\ninitialState = {\n    router      = Router.initialState\n  , categories  = []\n  , posts       = []\n  , post        = Nothing\n  }\n```\n\nNext step will be the definition of application routes:\n```elm\ntype Route = Home | NotFound | Static String | Category | Post\n\n-- Route list that is required by router.\n-- Note that routes which registered first have higher priority to be matched. So when you have concurrent routes, order of this list is important.\nroutes : List Route\nroutes = [\n    NotFound\n  , Static \"about\"\n  , Static \"contacts\"\n  , Home\n  , Category\n  , Post\n  ]\n```\n\nAnother thing that we need to define is a mapping between routes and route configurations:\n\n```elm\nimport Router.Types exposing (RouteConfig)\nimport URL.Segments as Segments exposing ((\u003c/\u003e))\nimport URL.Route exposing ((//\u003e))\n\nrouteConfig : Route -\u003e RouteConfig Route State\nrouteConfig route = case route of\n  Home -\u003e {\n    route = Nothing //\u003e Segments.end,\n  , render = renderHome\n  , actions = [LoadCategories]\n  }\n  NotFound -\u003e {\n    route = Nothing //\u003e Segments.static \"404\",\n  , render = notFound\n  , actions = []\n  }\n  Static page -\u003e {\n    route = Nothing //\u003e Segments.static page\n  , render = renderStatic page\n  , actions = []\n  }\n  -- `category` and `subcategory` is dynamic route params\n  -- `category` param match only \"animals\", \"flowers\", \"colors\" because of its constraints\n  -- `subcategory` is optional and might be omitted\n  Category -\u003e {\n    route = Just Home //\u003e Segments.enum \"category\" [\"animals\", \"flowers\", \"colors\"] \u003c/\u003e Segments.maybe (Segments.string \"subcategory\")\n  , render = renderCategory\n  , actions = [LoadPosts]\n  }\n  -- `postId` argument must be an integer\n  Post -\u003e {\n    route = Just Route.Category //\u003e Segments.static \"post\" \u003c/\u003e Segments.int \"postId\"\n  , render = renderPost\n  , actions = [LoadPost]\n  }\n```\n\nRoute `Post` on the example above is rely on routes `Category` and `Home` - that means all actions binded to routes `Home`, `Category` and `Post` will be executed to enter to `Post` route. Full URL template that will match `Post` route will also be combined with its parent routes.\n\nEach handler provides named views: `Dict String Html` - these HTML parts are finally combined and rendered in application layout:\n\n```elm\nlayout : Router Route State -\u003e State -\u003e Dict String (Html (Action State)) -\u003e Html (Action State)\nlayout router _ views =\n  let\n    defaultHeader = Html.header [] [Html.text \"Default header\"]\n    defaultFooter = Html.footer [] [Html.text \"Default footer\"]\n    defaultBody = Html.div [] []\n  in Html.div [] [\n    Maybe.withDefault defaultHeader \u003c| Dict.get \"header\" views\n  , Maybe.withDefault defaultBody   \u003c| Dict.get \"body\" views\n  , Maybe.withDefault defaultFooter \u003c| Dict.get \"footer\" views\n  ]\n```\n\nFinally we could dispacth our application:\n\n```elm\nimport App.Actions exposing (update)\n\nmain = Router.dispatch\n  (noFx initialState)\n  (RouterConfig {\n    html5 = False\n  , removeTrailingSlash = True\n  , update = update\n  , onTransition = []\n  , layout = layout\n  , routes = routes\n  , routeConfig = routeConfig\n  , subscriptions = always Sub.none\n  })\n```\n\nSee [Example](https://github.com/apuchenkin/elm-nested-router/tree/master/example) ([Live demo](http://apuchenkin.github.io/elm-nested-router/example)) and [Tests](https://github.com/apuchenkin/elm-nested-router/tree/master/test/Test) for more details.\n\n[Advanced example](https://github.com/apuchenkin/aws.photo.service/tree/elm/client)\n\n### Currently supports\n-   [x] HTML5 push state\n-   [x] Route params\n-   [x] Params constraints (String, Int, Enum, Regexp)\n-   [x] Optional params\n-   [x] Named views\n\n### Future thoughts\n-   [ ] Query string parameters support\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapuchenkin%2Felm-nested-router","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapuchenkin%2Felm-nested-router","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapuchenkin%2Felm-nested-router/lists"}