miso

Getting started

Your first Component

The core type of miso is Component. To define one, use the component smart constructor (or its synonym vcomp). Below is a simple counter.

module Main where

import           Miso
import           Miso.Lens
import qualified Miso.Html.Element  as H
import qualified Miso.Html.Event    as HE
import qualified Miso.Html.Property as HP

--                    * - The type of the global context
--                    |  * - The props inherited from the parent Component
--                    |  |  * - The type of the current Component model
--                    |  |  |   * - The action that updates the model
--                    |  |  |   |
counter :: Component () () Int Action
counter = vcomp m u v
  where
    -- | Initial model value
    m :: Int
    m = 0

    u :: Action -> Effect () () Int Action
    u = \case
      Add      -> this += 1
      Subtract -> this -= 1

    v :: () -> () -> Int -> View () Int Action
    v _context _props x = vfrag
      [ H.button_ [ HE.onClick Add, HP.id_ "add" ] [ "+" ]
      , text (ms x)
      , H.button_ [ HE.onClick Subtract, HP.id_ "subtract" ] [ "-" ]
      ]

main :: IO ()
main = startApp defaultEvents counter

data Action
  = Add
  | Subtract
  deriving (Eq, Show)
The counter, runninglive
0
data CounterAction = Add | Subtract
  deriving (Show, Eq)

counter :: Component ctx () Int CounterAction
counter = component m u v
  where
    m = 0

    u = \case
      Add      -> this += 1
      Subtract -> this -= 1

    v _ () n =
      H.div_ [ HP.class_ "row" ]
        [ H.button_ [ HE.onClick Subtract ] [ "−" ]
        , H.strong_ [] [ text (ms n) ]
        , H.button_ [ HE.onClick Add ] [ "+" ]
        ]

Four type parameters follow every Component: the global context (shared by the whole tree), the props passed by the parent, the component's own model and the action type its update consumes. A top-level application fixes context and props to (); the App synonym spells that out:

type App model action = Component () () model action

startApp :: Eq model => Events -> App model action -> IO ()

Running it

We recommend startApp as the starting point — it sets up event listeners, performs the initial draw and assumes <body> is empty. The miso function (and prerender) assume <body> has already been populated by the result of view: instead of drawing, miso hydrates. If the structures do not match it falls back to drawing from scratch.

main :: IO ()
main = miso defaultEvents $ \uri -> counter   -- hydrate a prerendered page

Doing something on mount

It is possible to execute an initial action when a Component is first mounted with the mount hook (and, similarly, unmount):

data Action = Init | Add | Subtract

main :: IO ()
main = startApp defaultEvents counter { mount = Just Init }

update :: Action -> Effect () () Int Action
update = \case
  Init -> io_ (consoleLog "hello world!")
  ...