Getting started

Your first Component

The core type of miso is Component. To define one, use the component smart constructor. 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 four Component type parameters:
--   context - the type of the global context
--   props   - the props inherited from the parent
--   Int     - the type of the Component model
--   Action  - the action that updates the model
counter
  :: Component context props Int Action
counter = component m u v
  where
    -- | Initial model value
    m :: Int
    m = 0

    u :: Action
      -> Effect context props Int Action
    u = \case
      Add      -> this += 1
      Subtract -> this -= 1

    v :: Int
      -> View context props Int Action
    v 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 context props Int Action
update = \case
  Init -> io_ (consoleLog "hello world!")
  ...