{"id":20580107,"url":"https://github.com/simre1/reactive-markup-old2","last_synced_at":"2026-04-10T21:39:16.699Z","repository":{"id":47432028,"uuid":"464666370","full_name":"Simre1/reactive-markup-old2","owner":"Simre1","description":null,"archived":false,"fork":false,"pushed_at":"2022-11-17T20:15:36.000Z","size":1375,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-06T11:48:47.083Z","etag":null,"topics":["declarative-ui","gtk","haskell"],"latest_commit_sha":null,"homepage":"","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Simre1.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}},"created_at":"2022-02-28T22:36:26.000Z","updated_at":"2023-10-31T10:39:31.000Z","dependencies_parsed_at":"2023-01-23T09:16:04.968Z","dependency_job_id":null,"html_url":"https://github.com/Simre1/reactive-markup-old2","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Simre1/reactive-markup-old2","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Simre1%2Freactive-markup-old2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Simre1%2Freactive-markup-old2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Simre1%2Freactive-markup-old2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Simre1%2Freactive-markup-old2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Simre1","download_url":"https://codeload.github.com/Simre1/reactive-markup-old2/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Simre1%2Freactive-markup-old2/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31660626,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T17:19:37.612Z","status":"ssl_error","status_checked_at":"2026-04-10T17:19:13.364Z","response_time":98,"last_error":"SSL_read: 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":["declarative-ui","gtk","haskell"],"created_at":"2024-11-16T06:20:21.802Z","updated_at":"2026-04-10T21:39:16.683Z","avatar_url":"https://github.com/Simre1.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Reactive Markup\n\nReactive markup is a haskell library for declaratively defining user interfaces. It is currently still in development phase, so drastic changes happen regularly. \n\nSome of the features of this library are:\n  - Declarative components\n  - UI as a function from model to components\n  - Automatic updating of the UI on model changes\n  - Contexts to constrain where components can be used\n  - Customizable interpretation of components (currently, only a GTK backend is available)\n\nThis library tries to disallow all UI errors at compile time, so compiled code will definitely produce a working UI.  \n\n\nHere is a small code example and an image of the corresponding GTK UI:\n```\nimport ReactiveMarkup.Target.Gtk\nimport ReactiveMarkup\nimport Data.Void\n\n\nmain :: IO ()\nmain = do\n  runGtk app\n\nrenderGUI :: Markup Gtk Root Void\nrenderGUI = bold \"Hello Reactive Markup\"\n\napp :: App Gtk EmptyF Void\napp =\n  App\n    { appRender = \\_ -\u003e renderGUI,\n      appHandleEvent = absurd,\n      appInitialState = EmptyF,\n      appName = \"Hello Reactive Markup\"\n    }\n```\n\n![Gtk Hello Reactive-Markup example](hello.png)\n\n## How to build yourself\n\nFirst and foremost, you need to have GTK 4 installed! Then the following should do the trick:\n```\ngit clone https://github.com/Simre1/reactive-markup.git\ncd reactive-markup\ncabal build all\n```\n\nThis will build the `reactive-markup` library, the `reactive-markup-gtk` backend as well as the GTK examples. *Initial* compilation will take quite a while due to the GTK dependencies.\n\n## Use as a library\n\nTo use Reactive Markup as a library, you will have to clone the git repository and add the reactive-markup folder manually to your build environment. Otherwise, it can be used like any other haskell library.\n\n## Quick Tutorial\n\n### UI components\n\nYou can define your UI by builing up the `Markup` type using the available components like `text`, `button`, `column` and so on. For example, to create a list consisting of some text and a button:\n```haskell\ntextAndButton :: Markup Gtk Common Void\ntextAndButton = column \n  [ italic \"Some text\",\n    button \"Click me\"\n  ]\n```\n\nYou can use functions and let-expressions to factor out code and make reusable UI components.\n```haskell\ntextAndButton :: Markup Gtk Common Void\ntextAndButton = \n  let boldText = bold \"Bold text\"\n  in column \n    [ boldText,\n      italic boldText,\n      button \"Click me\"\n    ]\n```\n\n### Reacting to changes\n\nAssuming that you create your UI as a function from model state to components, then the UI will automatically update itself on model state changes. However, some boilerplate is needed.\n\nHere is an example:\n```haskell\nsearchComponent :: Dynamic Gtk Bool -\u003e Markup Gtk Common Void\nsearchComponent isBool = dynamicMarkup isBool $ \\actualIsBool -\u003e row \n  [if actualIsBool then \"Active\" else \"Inactive\"]\n```\n\nThe `Dynamic` part means that the `Bool` value may change. To actually get at the `Bool` value, you need to use `dynamicMarkup` which gives you access to the `Bool` value in the function argument `actualIsBool`. Whenever the `Bool` value changes, `dynamicMarkup` will use the given function to determine the new UI.\n\n### Handling Events\n\nComponents can spawn events which are then passed upwards implicitly through the component hierarchy.\n\nHere is a button which emits an event of type `Text` and the value \"Event message\":\n```haskell\nbuttonWithTextEvent :: Markup Gtk Common Text\nbuttonWithTextEvent = button \"Click\" (#click ?= \"Event message\")\n```\n\nTake note that the event type is part of the `Markup` type. This means that by looking at the type we can determine the type of the events that a component can spawn. `buttonWithTextEvent` spawns events of type `Text`.  \n\nIf we use `buttonWithTextEvent` within another component, then the resuling component also spawns events of type `Text`.\n\n```haskell\ncolumnWithTextEvent :: Markup Gtk Common Text\ncolumnWithTextEvent = column [ buttonWithTextEvent ]\n```\n\n### First dynamic behavior\n\nYou cannot directly create `Dynamic` values and you cannot directly interact with events either. However, there are components which you can use to do so.\n\nFor example `simpleLocalState`:\n\n```haskell\ncountingButton :: Markup Gtk Common Void\ncountingButton = simpleLocalState handleButtonClick initialState buttonWithNumber\n  where\n    initialState :: Int\n    initialState = 0\n\n    handleButtonClick :: () -\u003e Int -\u003e SimpleUpdate Int Void\n    handleButtonClick () state = setSimpleUpdate (state + 1) defSimpleUpdate\n    \n    buttonWithNumber :: Dynamic Gtk Int -\u003e Markup Gtk Common ()\n    buttonWithNumber int = dynamicMarkup int $ \\i -\u003e button (string $ show i) (#click ?~ ())\n```\n\n`simpleLocalState` allows you to have some local state for a component and update it based on events happening within that component. In this case, the local state is an int which stores how many times the button has been clicked. Whenever the button has been clicked `handleButtonClick` is used to increase the state by 1. `buttonWithNumber` defines how to create UI components based on the local state.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimre1%2Freactive-markup-old2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimre1%2Freactive-markup-old2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimre1%2Freactive-markup-old2/lists"}