╔═════════════════════════════════════════════════════════════════════════════╗
║                                                                             ║
║  ██╗  ██╗██╗   ██╗██████╗ ███████╗██████╗ ██████╗  ██████╗ ██╗     ███████╗ ║
║  ██║  ██║╚██╗ ██╔╝██╔══██╗██╔════╝██╔══██╗██╔══██╗██╔═══██╗██║     ██╔════╝ ║
║  ███████║ ╚████╔╝ ██████╔╝█████╗  ██████╔╝██████╔╝██║   ██║██║     █████╗   ║
║  ██╔══██║  ╚██╔╝  ██╔═══╝ ██╔══╝  ██╔══██╗██╔══██╗██║   ██║██║     ██╔══╝   ║
║  ██║  ██║   ██║   ██║     ███████╗██║  ██║██████╔╝╚██████╔╝███████╗███████╗ ║
║  ╚═╝  ╚═╝   ╚═╝   ╚═╝     ╚══════╝╚═╝  ╚═╝╚═════╝  ╚═════╝ ╚══════╝╚══════╝ ║
╚═════════════════════════════════════════════════════════════════════════════╝
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}

module Main where

import Data.Text (Text)
import Web.Atomic.CSS
import Web.Hyperbole

main :: IO ()
main = do
  run 3000 $ do
    liveApp quickStartDocument (runPage page)

page :: (Hyperbole :> es) => Page es '[Message]
page = do
  pure $ do
    hyper Message1 $ messageView "Hello"
    hyper Message2 $ messageView "World!"

data Message = Message1 | Message2
  deriving (Generic, ViewId)

instance HyperView Message es where
  data Action Message
    = Louder Text
    deriving (Generic, ViewAction)

  update (Louder msg) = do
    let new = msg <> "!"
    pure $ messageView new

messageView :: Text -> View Message ()
messageView msg = do
  button (Louder msg) ~ border 1 $ text msg
Single Page Applications (SPAs) require the programmer to write two programs: a Javascript client and a Server, which both must conform to a common API
Hyperbole allows us to instead write a single Haskell program which runs exclusively on the server. All user interactions are sent to the server for processing, and a sub-section of the page is updated with the resulting HTML.
There are frameworks that support this in different ways, including HTMX, Phoenix LiveView, and others. Hyperbole has the following advantages
  1. 100% Haskell
  2. Type safe views, actions, routes, and forms
  3. Elegant interface with little boilerplate
  4. VirtualDOM updates over sockets
  5. Easy to use
Like HTMX, Hyperbole extends the capability of UI elements, but it uses Haskell's type-system to prevent common errors and provide default functionality. Specifically, a page has multiple update targets called HyperViews. These are automatically targeted by any UI element that triggers an action inside them. The compiler makes sure that actions and targets match
Like Phoenix LiveView, it upgrades the page to a fast WebSocket connection and uses VirtualDOM for live updates
Like Elm, it uses an update function to process actions, but greatly simplifies the Elm Architecture by directly returning html instead of using a reducer. ViewState is optional. Effects are handled by Effectful. forms are easy to use with minimal boilerplate
Hyperbole depends heavily on the following frameworks:
Beginners - It uses some advanced Haskell features, and requires using Effectful. If you are learning Haskell, I recommend using Scotty instead. While it doesn't provide any interactivity, it will be much easier to trace everything that is going on and will help you learn faster.
Offline and Low-Latency Apps - Some apps really do need to interact instantly using complex client-side logic. Hyperbole has a Javascript API to layer in client-side code when you need it, and one could certainly clone Gmail or Facebook. However, if your team is big enough to hire separate Javascript developers, it's time to call yourself a "backend expert" and write an an API using Servant instead.
This site has detailed documentation with inline examples. Click the "source" link to see the real source code for the example. You'll also see some inline code references that link out to hackage
▶️ Continue to Basics