GUI framework that uses the web browser as a display.

Version on this page:
LTS Haskell 18.28:
Stackage Nightly 2021-06-14:
Latest on Hackage:

See all snapshots threepenny-gui appears in

BSD-3-Clause licensed by Heinrich Apfelmus
Maintained by Heinrich Apfelmus <apfelmus at quantentunnel dot de>
This version can be pinned in stack with:threepenny-gui-,8651

Build Status

Threepenny-gui is a GUI framework written in Haskell that uses the web browser as a display. It’s very easy to install. See the

Project homepage

for more information on what it does and can do for you as a library user.


The library comes with many examples, which can be found in the samples folder. Follow the link for more information on how to run them.

Technical overview

A program written with Threepenny is essentially a small web server that displays the user interface as a web page to any browser that connects to it.


The frequent communication between browser and server means that Threepenny is best used as a GUI server running on localhost.

The communication is done over a persistent connection using WebSockets.

If you want to reduce latency, the best option is to generate JavaScript code and run it on the client. Consider this approach similar to a shading language. Some means of producing JavaScript from Haskell might be:

  • Fay
  • HJScript
  • UHC

Alternatively, the JS can be written by the user directly and invoked via the JavaScript FFI from Threepenny.

Future ideas

HTML rendering mode

It might be nice in the case of search engines to merely generate a DOM and render it, so that search engines can read the pages.

UI libraries

qooxdoo — provides a feature-complete widget set. One could wrap this in a type-safe API from Threepenny and get a complete, stable UI framework for free. Most of the “immediate feedback” like dragging things here, switching tabs there, are taken care of by the framework. All that would be left would be to provide the domain configuration and business/presentation logic.

There are plenty more like this, but this is the first that springs to mind that is good.


Many thanks to everyone who contributed, provided feedback or simply wrote an application using Threepenny! In particular, many thanks to:

Heinrich Apfelmus, Daniel Austin, Steve Bigham, Ken Friis Larsen, Daniel Mlot, Tim C. Schröder and also Daniel Diaz, Alex Greif, Yuval Langer, JP Moresmau, Luke Palmer, Jens Peterson, Jaap van der Plas, rnons, Michael Snoyman, tailcalled

Special thanks to Chris Done for starting the precursor project Ji.


Changelog for the threepenny-gui package – Maintenance release

  • Bump dependencies to allow aeson 1.2
  • Bump dependencies to allow websockets 0.11 – Maintenance release

  • Bump dependencies to allow aeson 1.1
  • Bump dependencies to allow vector 0.12
  • Bump dependencies to allow websockets 0.10 – Maintenance and snapshot release

  • Reduce communication from browser to server when creating Elements. New function unsafeCreateJSObject to create JavaScript objects without waiting for a client response. #131
  • Implement escape sequence ‘%%’ for JavaScript FFI. #132.
  • Change type of onEvent function to allow unregistering events.
  • Add function timestamp for simple performance measurements.
  • Update JavaScript dependencies to jQuery 2.2.3
  • Adapt to GHC 8.0.1. #138
  • Bump dependencies to allow aeson 1.0
  • Bump dependencies to allow data-default 0.7
  • Bump dependencies to allow snap-core 1.0 and snap-server 1.0
  • Bump dependencies to allow template-haskell 2.11
  • Bump dependencies to allow websockest-snap 0.10 – Maintenance release

  • Bump dependencies to allow base 4.9
  • Bump dependencies to allow aeson 0.11 – Maintenance release

  • Bump dependencies to allow async 2.1
  • Bump dependencies to allow transformers 0.5 – Maintenance release.

  • Elements that have become unreachable, for instance because they have been removed from the DOM and are no longer reachable in the Haskell code, will be garbage collected again. Fix #109, #113.
  • Adjust dependencies.
  • Add <meta> tag to indicate UTF8 encoding in html file. #116 – Maintenance release.

  • Temporary fix for #109, which was causing event handlers to be discarded. Unfortunately, this means that elements are currently not garbage collected after they have been removed from the DOM tree. – Maintenance release.

  • Remove unused direct dependencies, in particular ** attoparsec-enumerator ** utf8-string ** MonadCatchIO-transformers ** time – Maintenance release.

  • The ADDR environment variable is now parsed correctly.
  • Now builds on GHC 7.8 and GHC 7.10
  • The example source code in the samples folder has been reorganized and consolidated. – Snapshot release.

  • The internals of the JavaScript FFI has been reimplemented completely. A new module Foreign.JavaScript exports a bare JavaScript FFI in case you want to write a custom GUI framework. However, the module Graphics.UI.Threepenny is not compatible with it, even though it builds on top of it.
  • The fields of Config type for server configuration are now prefixed with js instead of tp. Example: jsPort, jsStatic.
  • The functions loadFile and loadDirectory have been removed, as I felt that the jsStatic option is sufficient for most use cases. – Snapshot release.

  • Possibility to specify IP address to bind the server to.
  • FFI now supports callbacks into Haskell. Remove callDeferredFunction function.
  • Graphics.UI.Threepenny.Canvas.SVG for creating SVG elements and attributes.
  • 2D graphics API in Graphics.UI.Threepenny.Canvas is beginning to grow.
  • Bool is now correctly marshalled to JavaScript.
  • Text can now be marshalled to JavaScrtip. – Maintenance release.

  • Dependency bytestring >=0.9.2 is now implemented correctly.
  • Allow newer versions of aeson dependency.
  • Allow newer versions of network, transformers and template-haskell dependencies.
  • Helper scripts in the samples directory now assume that you use a cabal sandbox for development.
  • The UI monad is now an instance of the Applicative class. – Maintenance release.

  • Dependency on text package now from version 0.11 to 1.1.*.
  • Dependency on aeson package replaces the former dependency on the json package.
  • Unicode characters are now transmitted correctly to the browser. #75, #62.
  • Change default port number to 8023. #64 – Bugfix release.

  • Fix CSS bug for grid function. – Maintenance release.

  • Adjust package dependencies. – Snapshot release.

  • New UI monad for easier JavaScript FFI and recursion in FRP.
  • Garbage collection for DOM elements. (Unfortunately, this doesn’t support using custom HTML files anymore, see issue #60.)
  • First stab at widgets.
  • Bump dependencies to allow websockets 0.8 – Snapshot release.

  • Browser communication with WebSockets.
  • First stab at FRP integration. – Snapshot release.

  • First stab at easy JavaScript FFI.

  • Initial release.