{"id":13800047,"url":"https://github.com/purescript-concur/purescript-concur-react","last_synced_at":"2026-02-23T10:01:47.602Z","repository":{"id":58246179,"uuid":"110793494","full_name":"purescript-concur/purescript-concur-react","owner":"purescript-concur","description":"Concur UI Framework for Purescript","archived":false,"fork":false,"pushed_at":"2024-12-09T13:13:48.000Z","size":14563,"stargazers_count":271,"open_issues_count":16,"forks_count":16,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-10-22T15:34:20.484Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://purescript-concur.github.io/purescript-concur-react","language":"PureScript","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/purescript-concur.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-11-15T06:34:17.000Z","updated_at":"2025-08-26T04:33:51.000Z","dependencies_parsed_at":"2024-06-20T22:09:28.051Z","dependency_job_id":null,"html_url":"https://github.com/purescript-concur/purescript-concur-react","commit_stats":null,"previous_names":["ajnsit/purescript-concur-react","ajnsit/purescript-concur"],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/purescript-concur/purescript-concur-react","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-concur%2Fpurescript-concur-react","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-concur%2Fpurescript-concur-react/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-concur%2Fpurescript-concur-react/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-concur%2Fpurescript-concur-react/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/purescript-concur","download_url":"https://codeload.github.com/purescript-concur/purescript-concur-react/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-concur%2Fpurescript-concur-react/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27675641,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-12T02:00:06.775Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2024-08-04T00:01:08.713Z","updated_at":"2025-12-12T03:29:49.609Z","avatar_url":"https://github.com/purescript-concur.png","language":"PureScript","readme":"\u003ch1 align=\"center\"\u003e\n  Purescript Concur\n\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\n   \u003cimg src=\"docs/logo.png\" height=\"100\"\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://gitter.im/concurhaskell\" rel=\"nofollow\"\u003e\n      \u003cimg src=\"https://camo.githubusercontent.com/9fb4e2dde684214e7454d930a369f97190d1ecf2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6769747465722d6a6f696e253230636861742532302545322538362541332d626c75652e737667\" alt=\"Join the chat at https://gitter.im/concurhaskell\" data-canonical-src=\"https://img.shields.io/badge/gitter-join%20chat%20%E2%86%A3-blue.svg\" style=\"max-width:100%;\"\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://www.reddit.com/r/concurhaskell/\" rel=\"nofollow\"\u003e\n      \u003cimg src=\"https://img.shields.io/badge/reddit-join%20the%20discussion%20%E2%86%A3-1158c2.svg\" alt=\"Join the chat at https://gitter.im/concurhaskell\" style=\"max-width:100%;\"\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://pursuit.purescript.org/packages/purescript-concur-react\"\u003e\n     \u003cimg src=\"https://pursuit.purescript.org/packages/purescript-concur-react/badge\"\n        alt=\"Purescript-Concur-React on Pursuit\"\u003e\n     \u003c/img\u003e\n   \u003c/a\u003e\n\u003c/p\u003e\n\n[Concur UI Lib](https://github.com/ajnsit/concur) is a brand new client side Web UI framework that explores an entirely new paradigm. It does not follow FRP (think Reflex or Reactive Banana), or Elm architecture, but aims to combine the best parts of both. This repo contains the Concur implementation for Purescript, using the React backend.\n\n## Documentation\n\nWork in progress tutorials are published in the [Concur Documentation site](https://github.com/ajnsit/concur-documentation/blob/master/README.md)\n\nAPI documentation is [published on Pursuit](https://pursuit.purescript.org/packages/purescript-concur-react).\n\n## Performance\n\nPurescript-Concur is reasonably light. The [entire *uncompressed* JS bundle](https://github.com/purescript-concur/purescript-concur-react/blob/master/docs/index.prod.minified.0dfb135e.js), including react and all libraries, for the entire example application in this repo clocks in at 180KB. You can build this bundle yourself with the command `npm run prod` (*currently broken* due to the move to spago).\n\nThis leads to pretty fast initial load times. Running the Chrome audit on https://purescript-concur.github.io/purescript-concur-react/ produces -\n\n\u003cp align=\"center\"\u003e\n   \u003cimg src=\"docs/Purescript-Concur-Performance.png\"\u003e\n\u003c/p\u003e\n\n## Ports to other languages\n\nConcur's model translates well to other platforms.\n\n1. [Concur for Haskell](https://github.com/ajnsit/concur) - The original version of Concur written in Haskell.\n2. [Concur for Javascript](https://github.com/ajnsit/concur-js) - An official but experimental port to Javascript.\n3. [Concur for Python](https://github.com/potocpav/python-concur) - An unofficial and experimental port to Python. Uses ImgUI for graphics. Created and Maintained by [potocpav](https://github.com/potocpav).\n\n## Installation\n\nYou can quickly get a production setup going (using Spago and Parcel) by cloning the [Purescript Concur Starter](https://github.com/purescript-concur/purescript-concur-starter).\n\nElse, if you use Spago -\n\n```bash\nspago install concur-react\n```\n\n## Building examples from source\n\n```bash\ngit clone https://github.com/purescript-concur/purescript-concur-react.git\ncd purescript-concur-react\nnpm install\n# Build library sources\nnpm run build\n# Build examples\nnpm run examples\n# Start a local server\nnpm run examples-start\n# Check examples\nopen localhost:1234 in the browser\n```\n\n## Exporting Concur Widgets to React JS\n\nConcur Widgets can be exported as both React classes or React Elements, which would allow them to be used within Javascript code.\n\nLet's say you have a `counter :: Int -\u003e Widget HTML a` concur widget that you want to expose to React.\n\n*Step 1*: Convert the `Widget` to a `ReactClass` using `Concur.React.toReactClass`. Here you would like the react class to accept a `{conut :: Int}` as props.\n\nHere, the `\"Counter\"` is the name of the component that will be visible to React. You can use any name.\nAnd `mempty` represents the initial view shown until the widget has finished initialising. We can leave this empty (views have a `Monoid` instance).\n\n```purescript\n-- Counter.purs\ncounterReactClass :: ReactClass { count :: Int }\ncounterReactClass = toReactClass \"Counter\" mempty \\ {count: i} -\u003e counter i\n```\n\n*Step 2*: Import the class from within Javascript, and give it a name starting with an uppercase letter as required by React.\n\n```javascript\n// MyApp.jsx\nimport {counterClass} from '\u003cpath/to/output/folder\u003e/Counter/index.js';\n\n// React requires all component names to start with an uppercase letter -\nlet Counter = counterClass;\n```\n\n*Step 3*: Now you can use it normally from within React.\n\n```javascript\n// MyApp.jsx\nclass ReactComponent extends Component {\n  render(props) {\n    let {count} = this.state;\n    return (\n      \u003cdiv\u003e\n        \u003ch4\u003eThe counter below was imported from a Concur widget. The starting count of 10 was passed from within React\u003c/h4\u003e\n        \u003cCounter count={10} /\u003e\n      \u003c/div\u003e\n    );\n}\n```\n\n## Using External React Components\n\nIt's easy to add external React components to Concur. Usually all you would require to wrap an external component is to import it as a `ReactClass`, and then wrapping it with one of the `el` functions.\n\nFor example, let's say you want to wrap the `Button` component provided by the material-ui library.\n\n*Step 1*: First write an FFI module that exposes the `ReactClass` component -\n\n```javascript\n// Button.js\nexports.classButton =  require('@material-ui/core/Button').default\n```\n\nAnd import it into your purescript program\n\n```purescript\n-- Button.purs\nforeign import classButton :: forall a. ReactClass a\n```\n\nIf you are using the [Purescript React MUI bindings](https://github.com/doolse/purescript-react-mui), then you can simply import the class component from the library without defining the FFI module -\n\n```purescript\nimport MaterialUI.Button (classButton)\n```\n\n*Step 2*: Then wrap up the imported `ReactClass` into a widget to make it usable within Concur -\n\n```purescript\nimport Concur.React.DOM (El, el')\nimport React (unsafeCreateElement)\nimport React.DOM.Props (unsafeFromPropsArray)\n\nbutton :: El\nbutton = el' (unsafeCreateElement classButton \u003c\u003c\u003c unsafeFromPropsArray)\n```\n\n*Step 3*: Now you can use `button` normally within Concur. For example -\n\n```purescript\nimport Concur.React.DOM as D\nimport Concur.React.Props as P\n\nhelloButton = button [P.onClick] [D.text \"Hello World!\"]\n```\n\nNote that you can mix in the default widgets and props with the MUI ones.\n\n\n## Examples\n\n[Demo](https://purescript-concur.github.io/purescript-concur-react/) and [Source](https://github.com/purescript-concur/purescript-concur-react/blob/master/examples/src/Main.purs) for composing all the examples in one page.\n\nIndividual example sources -\n\n1. **Hello World!** Shows simple effectful widgets with state using StateT. [Source](https://github.com/purescript-concur/purescript-concur-react/blob/master/examples/src/Test/Hello.purs).\n2. **A simple counter widget** without using StateT. [Source](https://github.com/purescript-concur/purescript-concur-react/blob/master/examples/src/Test/Counter.purs).\n3. **Focus counter** demonstrates a stateful widget, with multiple event handlers, and no action types needed! [Source](https://github.com/purescript-concur/purescript-concur-react/blob/master/examples/src/Test/FocusCount.purs).\n4. **Virtual Keyboard** An onscreen virtual keyboard. Demonstrates FFI as well as handling document level events inside nested widgets. [Source](https://github.com/purescript-concur/purescript-concur-react/blob/master/examples/src/Test/Keyboard.purs).\n5. **A login widget**. [Source](https://github.com/purescript-concur/purescript-concur-react/blob/master/examples/src/Test/Login.purs).\n6. Concur has Signals! Sample **counting widget implemented with Signals**! [Source](https://github.com/purescript-concur/purescript-concur-react/blob/master/examples/src/Test/Signals.purs).\n7. A **Full-featured TodoMVC implementation with LocalStorage Persistence** built with Signals. [Source](https://github.com/purescript-concur/purescript-concur-react/blob/master/examples/src/Test/Todos.purs).\n8. A **Fully editable tree** in ~30 lines of code (with Signals). [Source](https://github.com/purescript-concur/purescript-concur-react/blob/master/examples/src/Test/EditHeadingsSignals.purs).\n9. A **Postfix calculator**. [Source](https://github.com/purescript-concur/purescript-concur-react/blob/master/examples/src/Test/Calc.purs).\n10. Using **AJAX and handling JSON** responses. [Source](https://github.com/purescript-concur/purescript-concur-react/blob/master/examples/src/Test/Ajax.purs).\n11. A small widget to **Visualise CSS color codes**. [Source](https://github.com/purescript-concur/purescript-concur-react/blob/master/examples/src/Test/Color.purs).\n12. **Asynchronous timers** which can be cancelled. [Source](https://github.com/purescript-concur/purescript-concur-react/blob/master/examples/src/Test/Timers.purs).\n13. A **Routed widget** which demonstrates routing. [Source](https://github.com/purescript-concur/purescript-concur-react/blob/master/examples/src/Test/Routing.purs).\n14. **The Elm Architecture example** demonstrates how Concur subsumes \"The Elm Architecture\". [Source](https://github.com/purescript-concur/purescript-concur-react/blob/master/examples/src/Test/TheElmArchitecture.purs).\n15. **Performance test** - A huge list of 50 thousand parallel buttons. This has two variants, fast (uses slightly lower level interface) and slow (idiomatic concur code). [Source](https://github.com/purescript-concur/purescript-concur-react/blob/master/examples/src/Test/SlowButtonList.purs).\n16. **Tail Recursion demo** - Since Concur is purely functional in nature, its primary mode of iteration is via recursion. Purescript in general is NOT stack stafe with tail recursion; It uses tricks like tailRec and tailRecM. However, Concur performs trampolining to make monadic recursion completely stack safe. This example demonstrates that by making a huge number of tail recursive calls in a short span of time. [Source](https://github.com/purescript-concur/purescript-concur-react/blob/master/examples/src/Test/TailRec.purs).\n","funding_links":[],"categories":["UI Libraries"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpurescript-concur%2Fpurescript-concur-react","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpurescript-concur%2Fpurescript-concur-react","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpurescript-concur%2Fpurescript-concur-react/lists"}