{"id":13561592,"url":"https://github.com/emilianobovetti/elm-toast","last_synced_at":"2026-02-25T20:33:19.885Z","repository":{"id":57675058,"uuid":"336032243","full_name":"emilianobovetti/elm-toast","owner":"emilianobovetti","description":null,"archived":false,"fork":false,"pushed_at":"2025-06-09T22:16:46.000Z","size":34,"stargazers_count":13,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-06T21:56:13.052Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://package.elm-lang.org/packages/emilianobovetti/elm-toast/latest","language":"Elm","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/emilianobovetti.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-02-04T17:33:49.000Z","updated_at":"2025-06-09T22:16:01.000Z","dependencies_parsed_at":"2024-11-04T13:47:14.322Z","dependency_job_id":null,"html_url":"https://github.com/emilianobovetti/elm-toast","commit_stats":{"total_commits":4,"total_committers":1,"mean_commits":4.0,"dds":0.0,"last_synced_commit":"ef53d0b4243992d20a7613510939cf6de3534863"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/emilianobovetti/elm-toast","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emilianobovetti%2Felm-toast","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emilianobovetti%2Felm-toast/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emilianobovetti%2Felm-toast/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emilianobovetti%2Felm-toast/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/emilianobovetti","download_url":"https://codeload.github.com/emilianobovetti/elm-toast/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emilianobovetti%2Felm-toast/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29838112,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-25T19:08:47.527Z","status":"ssl_error","status_checked_at":"2026-02-25T18:59:04.705Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2024-08-01T13:00:58.900Z","updated_at":"2026-02-25T20:33:19.867Z","avatar_url":"https://github.com/emilianobovetti.png","language":"Elm","funding_links":[],"categories":["Elm"],"sub_categories":[],"readme":"# elm-toast\n\nA simple way to implement toast messages, [pop-up notifications](https://en.wikipedia.org/wiki/Pop-up_notification) or snackbars in the Elm architecture.\n\n`elm-toast` is a highly customizable library that handles a toast stack for you.\n\nSee online examples of a [trivial app](https://ellie-app.com/fz2FLpBJX4Sa1) and a [full-fledged thing](https://ellie-app.com/fz2DPCTmyvXa1) or run [example apps](https://github.com/emilianobovetti/elm-toast/tree/master/examples) on your machine.\n\n## Toast\n\nWe serve three kinds of toasts:\n\n```elm\nimport Toast\n\nfirst = Toast.persistent \"Hello, I'm a persistent toast\"\n\nsecond = Toast.expireIn 5000 \"I'm going to expire in five seconds\"\n\nthird = Toast.expireOnBlur 5000 \"I'll expire only if not focused\"\n```\n\nPersistent toasts will stay there until you take explicit action, they won't fade out automatically.\n\nThe second kind of toast, instead, will be removed after a fixed amount of time: in our example five seconds.\n\nLastly we have toasts that will only expire if the user is not interacting with them, if they receive focus or have mouse over, they have to wait the end of user's interaction and then five more seconds to fade out.\n\n## Tray\n\nToasts have to be served on a tray, and get an empty tray is as simple as:\n\n```elm\nimport Toast\n\nemptyTray : Toast.Tray String\nemptyTray =\n  Toast.tray\n```\n\nYou may have noticed that `Toast.Tray` is parametric and we are using the `String` type there. This is just the type of our own toast, it can be anything from a plain string, or a record to a whole new type.\n\n```elm\ntype Color\n    = Red\n    | Blue\n    | Green\n\ntype alias Toast =\n    { message : String\n    , color : Color\n    }\n\nemptyTray : Toast.Tray Toast\nemptyTray =\n  Toast.tray\n```\n\n## The Elm Architecture\n\nNow that we have both toast and tray we are almost done, we just need to plug some wires:\n\n### Setup types\n\nWe'll declare our `Toast` type, then application's `Model` and `Msg`.\n\n```elm\nimport Toast\n\ntype Color\n    = Red\n    | Green\n    | Blue\n\ntype alias Toast =\n    { message : String\n    , color : Color\n    }\n\n{- Let's store our tray here -}\ntype alias Model =\n    { tray : Toast.Tray Toast }\n\n{- We need a variant that contains Toast.Msg -}\ntype Msg\n    = ToastMsg Toast.Msg\n    | AddToast Toast\n```\n\n### Init function\n\nWe'll create a model with an empty tray and schedule toast insertion using `Task.perform` and `Process.sleep`.\n\n```elm\nimport Process\nimport Task\n\ndelay : Int -\u003e msg -\u003e Cmd msg\ndelay ms msg =\n    Task.perform (always msg) (Process.sleep \u003c| toFloat ms)\n\n{- Create a model with an empty tray and schedule toast insertions -}\ninit : () -\u003e ( Model, Cmd Msg )\ninit () =\n    ( { tray = Toast.tray }\n    , Cmd.batch\n        [ delay 0 (AddToast { message = \"hello, world\", color = Green })\n        , delay 500 (AddToast { message = \"I'm red\", color = Red })\n        , delay 1000 (AddToast { message = \"...and I'm blue\", color = Blue })\n        ]\n    )\n```\n\n### Update function\n\nWe have two messages right now: for `AddToast` we'll create a persistent toast and add it to app tray, for `ToastMsg` we have to forward its content to `Toast.update` and update our app accordingly.\n\n```elm\nupdate : Msg -\u003e Model -\u003e ( Model, Cmd Msg )\nupdate msg model =\n    case msg of\n        AddToast content -\u003e\n            let\n                ( tray, tmesg ) =\n                    Toast.add model.tray (Toast.persistent content)\n            in\n            ( { model | tray = tray }, Cmd.map ToastMsg tmesg )\n\n        ToastMsg tmsg -\u003e\n            let\n                ( tray, newTmesg ) =\n                    Toast.update tmsg model.tray\n            in\n            ( { model | tray = tray }, Cmd.map ToastMsg newTmesg )\n```\n\n### View function\n\nThe main actor here is call to `Toast.render`, it receives a `viewToast` function, our toast tray and a `Toast.Config Msg`.\n\nFirst thing you'll notice in following snippet is that toast view is completely delegated to the user, `elm-toast` makes almost no assumption on how it should be done.\n\n```elm\nimport Html exposing (Html)\nimport Html.Attributes exposing (style)\n\nview : Model -\u003e { title : String, body : List (Html Msg) }\nview model =\n    { title = \"Yay! elm-toast\"\n    , body = [ Toast.render viewToast model.tray (Toast.config ToastMsg) ]\n    }\n\nviewToast : List (Html.Attribute Msg) -\u003e Toast.Info Toast -\u003e Html Msg\nviewToast attributes toast =\n    Html.div\n      (toastStyles toast ++ attributes)\n      [ Html.text toast.content.message ]\n\ntoastStyles : Toast.Info Toast -\u003e List (Html.Attribute msg)\ntoastStyles toast =\n    let\n        background : Html.Attribute msg\n        background =\n            case toast.content.color of\n                Red -\u003e\n                    style \"background\" \"#f77\"\n\n                Green -\u003e\n                    style \"background\" \"#7f7\"\n\n                Blue -\u003e\n                    style \"background\" \"#77f\"\n    in\n    [ background\n    , style \"width\" \"110px\"\n    , style \"font-size\" \"18px\"\n    , style \"padding\" \"10px\"\n    , style \"margin\" \"10px\"\n    ]\n```\n\n### Putting it all together\n\nExport a `Browser.document` at this point is trivial.\n\n```elm\nmodule MyApp exposing (main)\n\nimport Browser\n\nmain : Program () Model Msg\nmain =\n    Browser.document\n        { init = init\n        , view = view\n        , update = update\n        , subscriptions = \\_ -\u003e Sub.none\n        }\n```\n\nIt's worth noting that we could use `Toast.tuple` to refactor our `update` function:\n\n```elm\nupdate : Msg -\u003e Model -\u003e ( Model, Cmd Msg )\nupdate msg model =\n    case msg of\n        AddToast content -\u003e\n            Toast.persistent content\n                |\u003e Toast.add model.tray\n                |\u003e Toast.tuple ToastMsg model\n\n        ToastMsg tmsg -\u003e\n            Toast.update tmsg model.tray\n                |\u003e Toast.tuple ToastMsg model\n```\n\n## You Might Ask\n#### (aka FAQ not really asked)\n\n### Can I add a delay to show an exit transition on toast fade out?\n\nOf course, you can use `withExitTransition` passing the number of milliseconds between the moment the toast is exiting and the moment the toast is removed.\n\n```elm\nToast.persistent content\n    |\u003e Toast.withExitTransition 1000\n    |\u003e Toast.add model.tray\n    |\u003e Toast.tuple ToastMsg model\n```\n\n### Can I have toasts with unique content?\n\nThere are three functions to achieve that: [addUnique](https://package.elm-lang.org/packages/emilianobovetti/elm-toast/latest/Toast#addUnique), [addUniqueBy](https://package.elm-lang.org/packages/emilianobovetti/elm-toast/latest/Toast#addUniqueBy) and [addUniqueWith](https://package.elm-lang.org/packages/emilianobovetti/elm-toast/latest/Toast#addUniqueWith).\n\n### How can I programmatically remove a toast?\n\nOne of these two functions: [remove](https://package.elm-lang.org/packages/emilianobovetti/elm-toast/latest/Toast#remove) or [exit](https://package.elm-lang.org/packages/emilianobovetti/elm-toast/latest/Toast#exit).\n\nE.g.:\n\n```elm\ntype alias Toast = { message : String }\n\nviewToast : List (Html.Attribute Msg) -\u003e Toast.Info Toast -\u003e Html Msg\nviewToast attributes toast =\n    Html.div\n        attributes\n        [ Html.text toast.content.message\n        , Html.div\n            [ onClick (ToastMsg \u003c| Toast.exit toast.id) ]\n            [ Html.text \"close\" ]\n        ]\n```\n\nThe difference between those two is pretty simple: if you `remove` a toast it'll be deleted right away, if `exit` is used the toast will go through its fade-out cycle, so [exitTransition](https://package.elm-lang.org/packages/emilianobovetti/elm-toast/latest/Toast#withExitTransition) milliseconds are waited before the toast is removed.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femilianobovetti%2Felm-toast","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Femilianobovetti%2Felm-toast","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femilianobovetti%2Felm-toast/lists"}