We've used button to trigger a Action in quite a few examples. Some actions require custom input from the user. For example search allows the user to freely input text. Notice that instead of a full action, it requires a partially applied action constructor Text -> Action id, and a delay in ms before sending changes to the server.
instance HyperView CustomText es where
  data Action CustomText
    = ShowInput
    deriving (Generic, ViewAction)

  update ShowInput = do
    t <- inputValue
    pure $ viewCustom t

customText :: View CustomText ()
customText = do
  search ShowInput 250 ~ border 1 . pad 10 @ placeholder "Type something"
Hyperbole provides a few other high-level inputs to tie interactivity to an Action, such as dropdown, and option. Notice how we again use a partially-applied constructor, this time with a custom UserInput
instance HyperView Dropper es where
  data Action Dropper
    = Select
    deriving (Generic, ViewAction)

  update Select = do
    mp :: Maybe Planet <- inputValue
    pure $ selectPlanet mp

data Planet
  = Mercury
  | Venus
  | Earth
  | Mars
  deriving (Generic, ToJSON, FromJSON, Eq, Show, InputValue)

selectPlanet :: Maybe Planet -> View Dropper ()
selectPlanet mp = do
  dropdown Select mp ~ border 1 . pad 10 $ do
    option Nothing "Choose a Planet"
    option (Just Mercury) "Mercury"
    option (Just Venus) "Venus"
    option (Just Earth) "Earth"
    option (Just Mars) "Mars"
  case mp of
    Nothing -> none
    Just p -> el $ text $ "You chose: " <> pack (show p)
For a more in-depth example see Filter
Views like button and dropdown make use of lower-level events like onClick, onKeyDown, and onInput. These events can be used directly:
viewEvents :: Text -> View TryEvents ()
viewEvents t = do
  el ~ bold $ text t
  input @ onInput SetMessage 250 ~ border 1 . pad 5 $ none
  button @ onDblClick ClearMessage ~ btn $ "Double Click to Clear"
 where
  input = tag "input"
  button = tag "button"
Some events should be used with caution, like onMouseEnter and onMouseLeave. Remember it is better to use Atomic CSS to provide immediate feedback whenever possible. If used improperly, too many mouse events could make the app unresponsive
viewBoxes :: Maybe Int -> View Boxes ()
viewBoxes mn = do
  boxes mn $ \n -> do
    el ~ box @ onMouseEnter (SelectBox n) . onMouseLeave ClearBox $ text $ pack $ show n
For a more in-depth example see Autocomplete
Include custom js on a page with the script tag on only the page where it is needed, or globally via your document function
page :: (Hyperbole :> es) => Page es '[JBoxes, Message]
page = do
  pure $ do
    script "custom.js"
    hyper JBoxes $ viewJBoxes Nothing
    hyper Message viewMessage
RunAction
JS can call the server with an API attached to window.Hyperbole. Here we re-implement mouseover boxes using Javascript
let boxes = Hyperbole.hyperView("JBoxes")
console.log("Found HyperView 'Boxes'")

boxes.addEventListener("mouseover", function(e) {
  if (e.target.classList.contains("box")) {
    let action = Hyperbole.action("Selected", parseInt(e.target.innerHTML))
    boxes.runAction(action)
  }
})
boxes.addEventListener("mouseout", function(e) {
  if (e.target.classList.contains("box")) {
    boxes.runAction("Clear")
  }
})
PushEvent
The server can push a Javascript event to be dispatched on a HyperView
  update AlertMe = do
    pushEvent "server-message" ("hello" :: Text)
    pure "Sent 'server-message' event"
function listenServerEvents() {
  // you can listen on document instead, the event will bubble
  Hyperbole.hyperView("Message").addEventListener("server-message", function(e) {
    alert("Server Message: " + e.detail)
  })
}
▶️ Continue to Examples