diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,6 @@
-Copyright (c) 2015 Sumit Sahrawat
+The MIT License (MIT)
+
+Copyright (c) 2021 David Davó
 
 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
diff --git a/MsgSpec.md b/MsgSpec.md
--- a/MsgSpec.md
+++ b/MsgSpec.md
@@ -1,7 +1,9 @@
-# IPython widget messaging specification
+# IPython widget messaging specification version 2
 
-> Largely based on: https://github.com/ipython/ipython/wiki/IPEP-23:-Backbone.js-Widgets
+The model implemented is the Model State v8, for ipywidgets 7.4., @jupyter-widgets/base 1.1., and @jupyter-widgets/controls 1.4.*.
 
+> Largely based on: https://github.com/jupyter-widgets/ipywidgets/blob/master/packages/schema/messages.md
+
 > The messaging specification as detailed is riddled with assumptions the IHaskell widget
 > implementation makes. It works for us, so it should work for everyone.
 
@@ -14,37 +16,73 @@
 
 > The comm should be opened with a `target_name` of `"ipython.widget"`.
 
+> The comm_open message's metadata gives the version of the widget messaging protocol, i.e., `{'version': '2.0.0'}`
+
 Any *numeric* property initialized with the empty string is provided the default value by the
 frontend. Some numbers need to be sent as actual numbers (when non-null), whereas the ones representing
-lengths in CSS units need to be sent as strings.
-
-The initial state must *at least* have the following fields:
-
-  - `msg_throttle` (default 3): To prevent the kernel from flooding with messages, the messages from
-    the widget to the kernel are throttled. If `msg_throttle` messages were sent, and all are still
-    processing, the widget will not send anymore state messages.
+lengths in CSS units need to be sent as strings specifying the size unit (px,em,cm,etc.).
 
-  - `_view_name` (depends on the widget): The frontend uses a generic model to represent
-    widgets. This field determines how a set of widget properties gets rendered into a
-    widget. Has the form `IPython.<widgetname>`, e.g `IPython.Button`.
+The initial state must *at least* have the following fields in the `data.state` value of the message:
 
-  - `_css` (default value = empty list): A list of 3-tuples, (selector, key, value).
+  - `_model_module`
+  - `_model_module_version`
+  - `_model_name`
+  - `_view_module`
+  - `_view_module_version`
+  - `_view_name`
 
-  - `visible` (default = True): Whether the widget is visible or not.
+You can see more info on the model state of widgets [here](https://github.com/jupyter-widgets/ipywidgets/blob/master/packages/schema/jupyterwidgetmodels.v8.md), or as a json definition [here](https://github.com/jupyter-widgets/ipywidgets/blob/79312fb164e058c3a2fddd9f3ef35493515ed64b/packages/schema/jupyterwidgetmodels.latest.json)
 
-  - Rest of the properties as required initially.
+> Warning!: By default there are two widgets modules: `@jupyter-widgets/controls` and `@jupyter-widgets/base`.
 
 This state is also used with fragments of the overall state to sync changes between the frontend and
 the kernel.
 
+### Buffer paths
+To display some widgets, we need to use the `buffer_paths`. It's only an array with arrays of keys on how to get to the fields that are to considered a
+byte stream. For example, in an image widget, `buffer_paths` would be the array `[ ["value"] ]`, which means that `state.value` is a buffer path. The buffers are sent in the header of the message, just before the data, so the n-th buffer corresponds to the n-th buffer path in the array.
+
+```json
+"data": {
+  "state": {
+    "value": ...,
+    ...
+  },
+  "buffer_paths": ["value"]
+}
+```
+
 ## Displaying widgets
 
 The creation of a widget does not display it. To display a widget, the kernel sends a display
-message to the frontend on the widget's comm.
+message to the frontend on the widget's iopub, with a custom mimetype instead of text/plain. Since 5.0, all custom json metadata should be encoded as a json object, instead of as a serialized string.
 
+The `version_major` and `version_minor` fields are the version number of the schema of this specific message
+(currently in sync with the WMP version). However, only the `model_id` field is required to display the widget.
+
+[Source](https://github.com/jupyter-widgets/ipywidgets/issues/3220)
+
 ```json
-{
-    "method": "display"
+method = "display_data",
+content = {
+    "data": {
+      "application/vnd.jupyter.widget-view+json": {
+      "model_id": "u-u-i-d",
+      "version_major": 2,
+      "version_minor": 0,
+    }
+}
+```
+
+## Clear output messages
+A simple message that indicates that the output of the header message id's should be cleaned.
+
+- `wait=true` indicates that it should clean the output in the next append, while `wait=false` cleans the output inmediately.
+
+```json
+method = "clear_output",
+content = {
+  "wait": bool
 }
 ```
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -5,3 +5,81 @@
 the backend is implemented in haskell.
 
 To know more about the widget messaging protocol, see [MsgSpec.md](MsgSpec.md).
+
+## Contributing examples
+If you want to contribute with more Notebook examples, please do so on the `Examples/`
+folder. Before commiting, please make sure they can be executed sequentialy and
+then remove the output from the Nootebooks with:
+
+```bash
+jupyter nbconvert *.ipynb --to notebook --inplace --clear-output
+```
+
+## Things to do
+- [ ] Automatic validation of the JSON implementation of widgets against the MsgSpec schema
+- [ ] Create integration tests for the widgets
+- [ ] Make the output widget capture output (problem: you have to get the message id of where the output is displayed)
+- [ ] Make the layout widget values more 'Haskelian': Instead of checking if the string is valid at runtime, make some types so it's checked at compile-time
+- [ ] Create a serializable color data type instead of using `Maybe String`
+- [ ] Overload setField so it can be used with `Maybes` or other wrapper types without having to put `Just` every time.
+- [ ] Add some "utils" work:
+    - [ ] Create media widget from file
+    - [ ] Get the selected label from a selection value
+
+## How to...
+This is a mini-guide for developers that want to update to a more recent widgets specification, but without
+dwelling into the deeps of the project
+
+### Add a new attribute
+If you want to add a new attribute you'll have to:
+1. Create a new singleton in [Singletons.hs](./Singletons.hs) inside the type `data Field`.
+2. Write the serialization key of the field as specified in the model (see [MsgSpec.md](./MsgSpec.md)) inside the `toKey` function at [Singletons.hs](./Singletons.hs)
+3. Because we use the `singletons-th` library, you have to define an alias for the attribute at [Common.hs](./Common.hs) to be able to use it at run-time more easily.
+4. Now you have to specify the type of the field. Edit the type family `Fieldtype` at [Types.hs](./Types.hs)
+
+### Add an attribute to a widget
+First you have to check if the attribute is only for one widget, or is from a common class. You can check it at [ipywidget's repo](https://github.com/jupyter-widgets/ipywidgets/tree/master/ipywidgets/widgets).
+
+- If it's only for one widget:
+    1. Edit the `type instance WidgetFields <WidgetNameType> = ...` at [Types.hs](./Types.hs), adding the new field to the field array.
+    2. Modify the `mk<WidgetName>` at `Module/WidgetName.hs`, adding the default value of the attribute. If the widget doesn't have any attributes yet, you can check how to do it on other widgets.
+- If it's for a common class:
+    1. Edit the `type <ClassName> = ...` at [Types.hs](./Types.hs)
+    2. Edit the `default<ClassName>Widget` function from the same file, adding the default value for that attribute.
+
+> Some widgets receive messages from the frontend when a value is modified (such as sliders, text areas, buttons...). You'll have to modify the `comm` function instantiated from the class `IHaskellWidget`. You can find an example at [IntSlider.hs](./Int/BoundedInt/IntSlider.hs)
+
+## FAQ
+When using widgets in ihaskell, you'll encounter a lot of compilation errors. If you are not very familiar with Haskell, they can be a bit hard to decipher, this is a mini guide that will (hopefully) appear when you paste the error in Google.
+
+### setField: No instance for...
+You probably got this error when trying to use setField like this:
+
+```
+<interactive>:1:1: error:
+    • No instance for (Data.Vinyl.Lens.RecElem
+                         Data.Vinyl.Core.Rec
+                         'ihaskell-widgets-0.3.0.0:IHaskell.Display.Widgets.Singletons.Index
+                         'ihaskell-widgets-0.3.0.0:IHaskell.Display.Widgets.Singletons.Index
+                         '[]
+                         '[]
+                         (Data.Vinyl.TypeLevel.RIndex 'ihaskell-widgets-0.3.0.0:IHaskell.Display.Widgets.Singletons.Index '[]))
+        arising from a use of ‘setField’
+    • In the expression: setField select Index 0
+      In an equation for ‘it’: it = setField select Index 0
+```
+
+What this error means is that there is no field called `Index` for this particular widget. You can display on screen all
+the fields available for a widget using `properties widget`.
+
+### setField: Couldn't match expected type SField f with actual type
+
+If you get an error like this, you probably forgot to put the field name in the second argument of `setField`.
+```
+<interactive>:1:25: error:
+    • Couldn't match expected type ‘ihaskell-widgets-0.3.0.0:IHaskell.Display.Widgets.Singletons.SField f’ with actual type ‘[a0]’
+    • In the second argument of ‘setField’, namely ‘["Apples", "Oranges", "Pears"]’
+      In the expression: setField selectMultiple ["Apples", "Oranges", "Pears"]
+      In an equation for ‘it’: it = setField selectMultiple ["Apples", "Oranges", "Pears"]
+    • Relevant bindings include it :: ihaskell-widgets-0.3.0.0:IHaskell.Display.Widgets.Types.FieldType f -> IO () (bound at <interactive>:1:1)
+```
diff --git a/ihaskell-widgets.cabal b/ihaskell-widgets.cabal
--- a/ihaskell-widgets.cabal
+++ b/ihaskell-widgets.cabal
@@ -10,7 +10,7 @@
 -- PVP summary:      +-+------- breaking API changes
 --                   | | +----- non-breaking API additions
 --                   | | | +--- code changes with no API change
-version:             0.2.3.3
+version:             0.4.0.0
 
 -- A short (one-line) description of the package.
 synopsis:            IPython standard widgets for IHaskell.
@@ -28,15 +28,17 @@
 license-file:        LICENSE
 
 -- The package author(s).
-author:              Sumit Sahrawat
+author:              David Davó
+                     Sumit Sahrawat
 
 -- An email address to which users can send suggestions, bug reports, and
 -- patches.
-maintainer:          Sumit Sahrawat <sumit.sahrawat.apm13@iitbhu.ac.in>,
+maintainer:          David Davó <david@ddavo.me>
+                     Sumit Sahrawat <sumit.sahrawat.apm13@iitbhu.ac.in>,
                      Andrew Gibiansky <andrew.gibiansky@gmail.com>
 
 -- A copyright notice.
--- copyright:
+copyright:           Copyright (c) 2021 David Davó
 
 -- category:
 
@@ -47,7 +49,7 @@
 extra-source-files:  README.md, MsgSpec.md
 
 -- Constraint on the version of Cabal needed to build this package.
-cabal-version:       >=1.10
+cabal-version:       1.16
 
 library
   ghc-options:         -Wall
@@ -58,37 +60,66 @@
   -- Modules exported by the library.
   exposed-modules:     IHaskell.Display.Widgets
                        IHaskell.Display.Widgets.Interactive
+                       IHaskell.Display.Widgets.Layout
 
   -- Modules included in this library but not exported.
   other-modules:       IHaskell.Display.Widgets.Button
+                       IHaskell.Display.Widgets.ColorPicker
+                       IHaskell.Display.Widgets.DatePicker
                        IHaskell.Display.Widgets.Box.Box
+                       IHaskell.Display.Widgets.Box.GridBox
+                       IHaskell.Display.Widgets.Box.HBox
+                       IHaskell.Display.Widgets.Box.VBox
                        IHaskell.Display.Widgets.Box.SelectionContainer.Accordion
                        IHaskell.Display.Widgets.Box.SelectionContainer.Tab
                        IHaskell.Display.Widgets.Bool.CheckBox
                        IHaskell.Display.Widgets.Bool.ToggleButton
                        IHaskell.Display.Widgets.Bool.Valid
+                       IHaskell.Display.Widgets.Controller.Controller
+                       IHaskell.Display.Widgets.Controller.ControllerAxis
+                       IHaskell.Display.Widgets.Controller.ControllerButton
                        IHaskell.Display.Widgets.Int.IntText
                        IHaskell.Display.Widgets.Int.BoundedInt.BoundedIntText
                        IHaskell.Display.Widgets.Int.BoundedInt.IntProgress
                        IHaskell.Display.Widgets.Int.BoundedInt.IntSlider
+                       IHaskell.Display.Widgets.Int.BoundedInt.Play
                        IHaskell.Display.Widgets.Int.BoundedIntRange.IntRangeSlider
+                       IHaskell.Display.Widgets.Link.Link
+                       IHaskell.Display.Widgets.Link.DirectionalLink
                        IHaskell.Display.Widgets.Float.FloatText
                        IHaskell.Display.Widgets.Float.BoundedFloat.BoundedFloatText
                        IHaskell.Display.Widgets.Float.BoundedFloat.FloatProgress
                        IHaskell.Display.Widgets.Float.BoundedFloat.FloatSlider
+                       IHaskell.Display.Widgets.Float.BoundedFloat.FloatLogSlider
                        IHaskell.Display.Widgets.Float.BoundedFloatRange.FloatRangeSlider
-                       IHaskell.Display.Widgets.Image
+                       IHaskell.Display.Widgets.Media.Audio
+                       IHaskell.Display.Widgets.Media.Image
+                       IHaskell.Display.Widgets.Media.Video
                        IHaskell.Display.Widgets.Output
                        IHaskell.Display.Widgets.Selection.Dropdown
                        IHaskell.Display.Widgets.Selection.RadioButtons
                        IHaskell.Display.Widgets.Selection.Select
+                       IHaskell.Display.Widgets.Selection.SelectionSlider
+                       IHaskell.Display.Widgets.Selection.SelectionRangeSlider
                        IHaskell.Display.Widgets.Selection.ToggleButtons
                        IHaskell.Display.Widgets.Selection.SelectMultiple
+                       IHaskell.Display.Widgets.String.Combobox
                        IHaskell.Display.Widgets.String.HTML
+                       IHaskell.Display.Widgets.String.HTMLMath
                        IHaskell.Display.Widgets.String.Label
+                       IHaskell.Display.Widgets.String.Password
                        IHaskell.Display.Widgets.String.Text
                        IHaskell.Display.Widgets.String.TextArea
+                       IHaskell.Display.Widgets.Style.ButtonStyle
+                       IHaskell.Display.Widgets.Style.DescriptionStyle
+                       IHaskell.Display.Widgets.Style.ProgressStyle
+                       IHaskell.Display.Widgets.Style.SliderStyle
+                       IHaskell.Display.Widgets.Style.ToggleButtonsStyle
 
+                       IHaskell.Display.Widgets.Layout.Common
+                       IHaskell.Display.Widgets.Layout.LayoutWidget
+                       IHaskell.Display.Widgets.Layout.Types
+
                        IHaskell.Display.Widgets.Types
                        IHaskell.Display.Widgets.Common
                        IHaskell.Display.Widgets.Singletons
@@ -98,6 +129,7 @@
 
   build-depends:       aeson >=0.7
                      , base >=4.9 && <5
+                     , bytestring
                      , containers >= 0.5
                      , ipython-kernel >= 0.6.1.2
                      , text >= 0.11
@@ -111,6 +143,9 @@
 					 -- The singletons package version is locked to the compiler
 					 -- so let cabal choose the right one.
                      , singletons -any
+
+  if impl (ghc >= 9.0)
+    build-depends:     singletons-base -any
 
   -- Directories containing source files.
   hs-source-dirs:      src
diff --git a/src/IHaskell/Display/Widgets.hs b/src/IHaskell/Display/Widgets.hs
--- a/src/IHaskell/Display/Widgets.hs
+++ b/src/IHaskell/Display/Widgets.hs
@@ -1,8 +1,22 @@
+{-|
+Module      : ihaskell-widgets
+Description : Jupyter Widgets implementation for the IHaskell kernel
+Copyright   : (c) Sumit Shrawat, 2015
+                  David Davó, 2021
+License     : MIT
+Maintainer  : david@ddavo.me
+Stability   : experimental
+-}
 module IHaskell.Display.Widgets (module X) where
 
 import           IHaskell.Display.Widgets.Button as X
+import           IHaskell.Display.Widgets.ColorPicker as X
+import           IHaskell.Display.Widgets.DatePicker as X
 
 import           IHaskell.Display.Widgets.Box.Box as X
+import           IHaskell.Display.Widgets.Box.GridBox as X
+import           IHaskell.Display.Widgets.Box.HBox as X
+import           IHaskell.Display.Widgets.Box.VBox as X
 import           IHaskell.Display.Widgets.Box.SelectionContainer.Accordion as X
 import           IHaskell.Display.Widgets.Box.SelectionContainer.Tab as X
 
@@ -10,34 +24,59 @@
 import           IHaskell.Display.Widgets.Bool.ToggleButton as X
 import           IHaskell.Display.Widgets.Bool.Valid as X
 
+import           IHaskell.Display.Widgets.Controller.Controller as X
+import           IHaskell.Display.Widgets.Controller.ControllerAxis as X
+import           IHaskell.Display.Widgets.Controller.ControllerButton as X
+
 import           IHaskell.Display.Widgets.Int.IntText as X
 import           IHaskell.Display.Widgets.Int.BoundedInt.BoundedIntText as X
 import           IHaskell.Display.Widgets.Int.BoundedInt.IntProgress as X
 import           IHaskell.Display.Widgets.Int.BoundedInt.IntSlider as X
+import           IHaskell.Display.Widgets.Int.BoundedInt.Play as X
 import           IHaskell.Display.Widgets.Int.BoundedIntRange.IntRangeSlider as X
 
+import           IHaskell.Display.Widgets.Link.Link as X
+import           IHaskell.Display.Widgets.Link.DirectionalLink as X
+
 import           IHaskell.Display.Widgets.Float.FloatText as X
 import           IHaskell.Display.Widgets.Float.BoundedFloat.BoundedFloatText as X
 import           IHaskell.Display.Widgets.Float.BoundedFloat.FloatProgress as X
 import           IHaskell.Display.Widgets.Float.BoundedFloat.FloatSlider as X
+import           IHaskell.Display.Widgets.Float.BoundedFloat.FloatLogSlider as X
 import           IHaskell.Display.Widgets.Float.BoundedFloatRange.FloatRangeSlider as X
 
-import           IHaskell.Display.Widgets.Image as X
+import           IHaskell.Display.Widgets.Media.Audio as X
+import           IHaskell.Display.Widgets.Media.Image as X
+import           IHaskell.Display.Widgets.Media.Video as X
 
 import           IHaskell.Display.Widgets.Output as X
 
 import           IHaskell.Display.Widgets.Selection.Dropdown as X
 import           IHaskell.Display.Widgets.Selection.RadioButtons as X
 import           IHaskell.Display.Widgets.Selection.Select as X
+import           IHaskell.Display.Widgets.Selection.SelectionSlider as X
+import           IHaskell.Display.Widgets.Selection.SelectionRangeSlider as X
 import           IHaskell.Display.Widgets.Selection.ToggleButtons as X
 import           IHaskell.Display.Widgets.Selection.SelectMultiple as X
 
+import           IHaskell.Display.Widgets.String.Combobox as X
 import           IHaskell.Display.Widgets.String.HTML as X
+import           IHaskell.Display.Widgets.String.HTMLMath as X
 import           IHaskell.Display.Widgets.String.Label as X
+import           IHaskell.Display.Widgets.String.Password as X
 import           IHaskell.Display.Widgets.String.Text as X
 import           IHaskell.Display.Widgets.String.TextArea as X
 
+import           IHaskell.Display.Widgets.Style.ButtonStyle as X
+import           IHaskell.Display.Widgets.Style.DescriptionStyle as X
+import           IHaskell.Display.Widgets.Style.ProgressStyle as X
+import           IHaskell.Display.Widgets.Style.SliderStyle as X
+import           IHaskell.Display.Widgets.Style.ToggleButtonsStyle as X
+
 import           IHaskell.Display.Widgets.Common as X
 import           IHaskell.Display.Widgets.Types as X (setField, getField, properties, triggerDisplay,
                                                       triggerChange, triggerClick, triggerSelection,
-                                                      triggerSubmit, ChildWidget(..))
+                                                      triggerSubmit, ChildWidget(..), StyleWidget(..),
+                                                      WidgetFieldPair(..), Date(..), unlink,
+                                                      JSONByteString(..), OutputMsg(..))
+
diff --git a/src/IHaskell/Display/Widgets/Bool/CheckBox.hs b/src/IHaskell/Display/Widgets/Bool/CheckBox.hs
--- a/src/IHaskell/Display/Widgets/Bool/CheckBox.hs
+++ b/src/IHaskell/Display/Widgets/Bool/CheckBox.hs
@@ -18,6 +18,7 @@
 import           Control.Monad (void)
 import           Data.Aeson
 import           Data.IORef (newIORef)
+import           Data.Vinyl (Rec(..), (<+>))
 
 import           IHaskell.Display
 import           IHaskell.Eval.Widgets
@@ -25,6 +26,8 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | A 'CheckBox' represents a Checkbox widget from IPython.html.widgets.
 type CheckBox = IPythonWidget 'CheckBoxType
@@ -34,8 +37,13 @@
 mkCheckBox = do
   -- Default properties, with a random uuid
   wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
-  let widgetState = WidgetState $ defaultBoolWidget "CheckboxView" "CheckboxModel"
+  let boolAttrs = defaultBoolWidget "CheckboxView" "CheckboxModel" layout $ StyleWidget dstyle
+      checkBoxAttrs = (Indent =:: True)
+                      :& RNil
+      widgetState = WidgetState $ boolAttrs <+> checkBoxAttrs
 
   stateIO <- newIORef widgetState
 
@@ -47,15 +55,10 @@
   -- Return the image widget
   return widget
 
-instance IHaskellDisplay CheckBox where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget CheckBox where
   getCommUUID = uuid
   comm widget val _ =
-    case nestedObjectLookup val ["sync_data", "value"] of
+    case nestedObjectLookup val ["state", "value"] of
       Just (Bool value) -> do
         void $ setField' widget BoolValue value
         triggerChange widget
diff --git a/src/IHaskell/Display/Widgets/Bool/ToggleButton.hs b/src/IHaskell/Display/Widgets/Bool/ToggleButton.hs
--- a/src/IHaskell/Display/Widgets/Bool/ToggleButton.hs
+++ b/src/IHaskell/Display/Widgets/Bool/ToggleButton.hs
@@ -26,6 +26,8 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | A 'ToggleButton' represents a ToggleButton widget from IPython.html.widgets.
 type ToggleButton = IPythonWidget 'ToggleButtonType
@@ -35,10 +37,11 @@
 mkToggleButton = do
   -- Default properties, with a random uuid
   wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
-  let boolState = defaultBoolWidget "ToggleButtonView" "ToggleButtonModel"
-      toggleState = (Tooltip =:: "")
-                    :& (Icon =:: "")
+  let boolState = defaultBoolWidget "ToggleButtonView" "ToggleButtonModel" layout $ StyleWidget dstyle
+      toggleState = (Icon =:: "")
                     :& (ButtonStyle =:: DefaultButton)
                     :& RNil
       widgetState = WidgetState (boolState <+> toggleState)
@@ -53,15 +56,10 @@
   -- Return the image widget
   return widget
 
-instance IHaskellDisplay ToggleButton where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget ToggleButton where
   getCommUUID = uuid
   comm widget val _ =
-    case nestedObjectLookup val ["sync_data", "value"] of
+    case nestedObjectLookup val ["state", "value"] of
       Just (Bool value) -> do
         void $ setField' widget BoolValue value
         triggerChange widget
diff --git a/src/IHaskell/Display/Widgets/Bool/Valid.hs b/src/IHaskell/Display/Widgets/Bool/Valid.hs
--- a/src/IHaskell/Display/Widgets/Bool/Valid.hs
+++ b/src/IHaskell/Display/Widgets/Bool/Valid.hs
@@ -9,7 +9,7 @@
   ( -- * The Valid Widget
     ValidWidget
     -- * Constructor
-  , mkValidWidget
+  , mkValid
   ) where
 
 -- To keep `cabal repl` happy when running from the ihaskell repo
@@ -25,17 +25,21 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | A 'ValidWidget' represents a Valid widget from IPython.html.widgets.
 type ValidWidget = IPythonWidget 'ValidType
 
 -- | Create a new output widget
-mkValidWidget :: IO ValidWidget
-mkValidWidget = do
+mkValid :: IO ValidWidget
+mkValid = do
   -- Default properties, with a random uuid
   wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
-  let boolState = defaultBoolWidget "ValidView" "ValidModel"
+  let boolState = defaultBoolWidget "ValidView" "ValidModel" layout $ StyleWidget dstyle
       validState = (ReadOutMsg =:: "") :& RNil
       widgetState = WidgetState $ boolState <+> validState
 
@@ -48,11 +52,6 @@
 
   -- Return the image widget
   return widget
-
-instance IHaskellDisplay ValidWidget where
-  display b = do
-    widgetSendView b
-    return $ Display []
 
 instance IHaskellWidget ValidWidget where
   getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/Box/Box.hs b/src/IHaskell/Display/Widgets/Box/Box.hs
--- a/src/IHaskell/Display/Widgets/Box/Box.hs
+++ b/src/IHaskell/Display/Widgets/Box/Box.hs
@@ -23,6 +23,7 @@
 import           IHaskell.IPython.Message.UUID as U
 
 import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
 
 -- | A 'Box' represents a Box widget from IPython.html.widgets.
 type Box = IPythonWidget 'BoxType
@@ -32,8 +33,9 @@
 mkBox = do
   -- Default properties, with a random uuid
   wid <- U.random
+  layout <- mkLayout
 
-  let widgetState = WidgetState $ defaultBoxWidget "BoxView" "BoxModel"
+  let widgetState = WidgetState $ defaultBoxWidget "BoxView" "BoxModel" layout
 
   stateIO <- newIORef widgetState
 
@@ -44,11 +46,6 @@
 
   -- Return the widget
   return box
-
-instance IHaskellDisplay Box where
-  display b = do
-    widgetSendView b
-    return $ Display []
 
 instance IHaskellWidget Box where
   getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/Box/GridBox.hs b/src/IHaskell/Display/Widgets/Box/GridBox.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Box/GridBox.hs
@@ -0,0 +1,51 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+
+module IHaskell.Display.Widgets.Box.GridBox
+  ( -- * The GridBox widget
+    GridBox
+    -- * Constructor
+  , mkGridBox
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+
+-- | A 'GridBox' represents a GridBox widget from IPython.html.widgets.
+type GridBox = IPythonWidget 'GridBoxType
+
+-- | Create a new GridBox
+mkGridBox :: IO GridBox
+mkGridBox = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+  layout <- mkLayout
+
+  let widgetState = WidgetState $ defaultBoxWidget "GridBoxView" "GridBoxModel" layout
+
+  stateIO <- newIORef widgetState
+
+  let gridBox = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen gridBox $ toJSON widgetState
+
+  -- Return the widget
+  return gridBox
+
+instance IHaskellWidget GridBox where
+  getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/Box/HBox.hs b/src/IHaskell/Display/Widgets/Box/HBox.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Box/HBox.hs
@@ -0,0 +1,51 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+
+module IHaskell.Display.Widgets.Box.HBox
+  ( -- * The HBox widget
+    HBox
+    -- * Constructor
+  , mkHBox
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+
+-- | A 'HBox' represents a HBox widget from IPython.html.widgets.
+type HBox = IPythonWidget 'HBoxType
+
+-- | Create a new HBox
+mkHBox :: IO HBox
+mkHBox = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+  layout <- mkLayout
+
+  let widgetState = WidgetState $ defaultBoxWidget "HBoxView" "HBoxModel" layout
+
+  stateIO <- newIORef widgetState
+
+  let hBox = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen hBox $ toJSON widgetState
+
+  -- Return the widget
+  return hBox
+
+instance IHaskellWidget HBox where
+  getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/Box/SelectionContainer/Accordion.hs b/src/IHaskell/Display/Widgets/Box/SelectionContainer/Accordion.hs
--- a/src/IHaskell/Display/Widgets/Box/SelectionContainer/Accordion.hs
+++ b/src/IHaskell/Display/Widgets/Box/SelectionContainer/Accordion.hs
@@ -26,6 +26,7 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
 
 -- | A 'Accordion' represents a Accordion widget from IPython.html.widgets.
 type Accordion = IPythonWidget 'AccordionType
@@ -35,8 +36,9 @@
 mkAccordion = do
   -- Default properties, with a random uuid
   wid <- U.random
+  layout <- mkLayout
 
-  let widgetState = WidgetState $ defaultSelectionContainerWidget "AccordionView" "AccordionModel"
+  let widgetState = WidgetState $ defaultSelectionContainerWidget "AccordionView" "AccordionModel" layout
 
   stateIO <- newIORef widgetState
 
@@ -48,16 +50,14 @@
   -- Return the widget
   return box
 
-instance IHaskellDisplay Accordion where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget Accordion where
   getCommUUID = uuid
   comm widget val _ =
-    case nestedObjectLookup val ["sync_data", "selected_index"] of
+    case nestedObjectLookup val ["state", "selected_index"] of
       Just (Number num) -> do
-        void $ setField' widget SelectedIndex (Sci.coefficient num)
+        void $ setField' widget SelectedIndex $ Just (Sci.coefficient num)
+        triggerChange widget
+      Just Null -> do
+        void $ setField' widget SelectedIndex Nothing
         triggerChange widget
       _ -> pure ()
diff --git a/src/IHaskell/Display/Widgets/Box/SelectionContainer/Tab.hs b/src/IHaskell/Display/Widgets/Box/SelectionContainer/Tab.hs
--- a/src/IHaskell/Display/Widgets/Box/SelectionContainer/Tab.hs
+++ b/src/IHaskell/Display/Widgets/Box/SelectionContainer/Tab.hs
@@ -9,12 +9,14 @@
   ( -- * The Tab widget
     TabWidget
     -- * Constructor
-  , mkTabWidget
+  , mkTab
   ) where
 
 -- To keep `cabal repl` happy when running from the ihaskell repo
 import           Prelude
 
+import           Control.Monad (void)
+
 import           Data.Aeson
 import           Data.IORef (newIORef)
 import qualified Data.Scientific as Sci
@@ -25,17 +27,19 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
 
 -- | A 'TabWidget' represents a Tab widget from IPython.html.widgets.
 type TabWidget = IPythonWidget 'TabType
 
 -- | Create a new box
-mkTabWidget :: IO TabWidget
-mkTabWidget = do
+mkTab :: IO TabWidget
+mkTab = do
   -- Default properties, with a random uuid
   wid <- U.random
+  layout <- mkLayout
 
-  let widgetState = WidgetState $ defaultSelectionContainerWidget "TabView" "TabModel"
+  let widgetState = WidgetState $ defaultSelectionContainerWidget "TabView" "TabModel" layout
 
   stateIO <- newIORef widgetState
 
@@ -47,16 +51,14 @@
   -- Return the widget
   return box
 
-instance IHaskellDisplay TabWidget where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget TabWidget where
   getCommUUID = uuid
   comm widget val _ =
-    case nestedObjectLookup val ["sync_data", "selected_index"] of
+    case nestedObjectLookup val ["state", "selected_index"] of
       Just (Number num) -> do
-        _ <- setField' widget SelectedIndex (Sci.coefficient num)
+        void $ setField' widget SelectedIndex $ Just (Sci.coefficient num)
+        triggerChange widget
+      Just Null -> do
+        void $ setField' widget SelectedIndex Nothing
         triggerChange widget
       _ -> pure ()
diff --git a/src/IHaskell/Display/Widgets/Box/VBox.hs b/src/IHaskell/Display/Widgets/Box/VBox.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Box/VBox.hs
@@ -0,0 +1,51 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+
+module IHaskell.Display.Widgets.Box.VBox
+  ( -- * The VBox widget
+    VBox
+    -- * Constructor
+  , mkVBox
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+
+-- | A 'VBox' represents a VBox widget from IPython.html.widgets.
+type VBox = IPythonWidget 'VBoxType
+
+-- | Create a new VBox
+mkVBox :: IO VBox
+mkVBox = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+  layout <- mkLayout
+
+  let widgetState = WidgetState $ defaultBoxWidget "VBoxView" "VBoxModel" layout
+
+  stateIO <- newIORef widgetState
+
+  let vbox = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen vbox $ toJSON widgetState
+
+  -- Return the widget
+  return vbox
+
+instance IHaskellWidget VBox where
+  getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/Button.hs b/src/IHaskell/Display/Widgets/Button.hs
--- a/src/IHaskell/Display/Widgets/Button.hs
+++ b/src/IHaskell/Display/Widgets/Button.hs
@@ -25,6 +25,8 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Style.ButtonStyle
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
 
 -- | A 'Button' represents a Button from IPython.html.widgets.
 type Button = IPythonWidget 'ButtonType
@@ -34,16 +36,16 @@
 mkButton = do
   -- Default properties, with a random uuid
   wid <- U.random
+  layout <- mkLayout
+  btnstyle <- mkButtonStyle
 
-  let dom = defaultDOMWidget "ButtonView" "ButtonModel"
-      but = (Description =:: "")
-            :& (Tooltip =:: "")
-            :& (Disabled =:: False)
+  let ddw = defaultDescriptionWidget "ButtonView" "ButtonModel" layout $ StyleWidget btnstyle
+      but = (Disabled =:: False)
             :& (Icon =:: "")
             :& (ButtonStyle =:: DefaultButton)
             :& (ClickHandler =:: return ())
             :& RNil
-      buttonState = WidgetState (dom <+> but)
+      buttonState = WidgetState (ddw <+> but)
 
   stateIO <- newIORef buttonState
 
@@ -54,11 +56,6 @@
 
   -- Return the button widget
   return button
-
-instance IHaskellDisplay Button where
-  display b = do
-    widgetSendView b
-    return $ Display []
 
 instance IHaskellWidget Button where
   getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/ColorPicker.hs b/src/IHaskell/Display/Widgets/ColorPicker.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/ColorPicker.hs
@@ -0,0 +1,67 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+
+module IHaskell.Display.Widgets.ColorPicker
+  ( -- * The ColorPicker Widget
+    ColorPicker
+    -- * Create a new ColorPicker
+  , mkColorPicker
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+import           Data.Vinyl (Rec(..), (<+>))
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
+
+-- | A 'ColorPicker' represents a ColorPicker from IPython.html.widgets.
+type ColorPicker = IPythonWidget 'ColorPickerType
+
+-- | Create a new ColorPicker
+mkColorPicker :: IO ColorPicker
+mkColorPicker = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
+
+  let ddw = defaultDescriptionWidget "ColorPickerView" "ColorPickerModel" layout $ StyleWidget dstyle
+      color = (StringValue =:: "black")
+              :& (Concise =:: False)
+              :& (Disabled =:: False)
+              :& (ChangeHandler =:: return ())
+              :& RNil
+      colorPickerState = WidgetState (ddw <+> color)
+
+  stateIO <- newIORef colorPickerState
+
+  let colorPicker = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen colorPicker $ toJSON colorPickerState
+
+  -- Return the ColorPicker widget
+  return colorPicker
+
+instance IHaskellWidget ColorPicker where
+  getCommUUID = uuid
+  comm widget val _ =
+    case nestedObjectLookup val ["state", "value"] of
+      Just o -> case fromJSON o of
+        Success (String color) -> setField' widget StringValue color >> triggerChange widget
+        _ -> pure ()
+      _ -> pure ()
diff --git a/src/IHaskell/Display/Widgets/Common.hs b/src/IHaskell/Display/Widgets/Common.hs
--- a/src/IHaskell/Display/Widgets/Common.hs
+++ b/src/IHaskell/Display/Widgets/Common.hs
@@ -6,6 +6,7 @@
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE AutoDeriveTypeable #-}
 {-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE CPP #-}
 
 -- There are lots of pattern synpnyms, and little would be gained by adding
 -- the type signatures.
@@ -16,7 +17,6 @@
 
 import           Data.Aeson
 import           Data.Aeson.Types (emptyObject)
-import           Data.HashMap.Strict as HM
 import           Data.Text (pack, Text)
 import           Data.Typeable (Typeable)
 
@@ -25,123 +25,203 @@
 
 import qualified IHaskell.Display.Widgets.Singletons as S
 
+#if MIN_VERSION_aeson(2,0,0)
+import qualified Data.Aeson.KeyMap as KeyMap
+import qualified Data.Aeson.Key    as Key
+#else
+import           Data.HashMap.Strict as HM
+#endif
+
+-- | The view module string
 pattern ViewModule = S.SViewModule
+-- | The view module version
+pattern ViewModuleVersion = S.SViewModuleVersion
+-- | The view name
 pattern ViewName = S.SViewName
+-- | The model module string
 pattern ModelModule = S.SModelModule
+-- | The model module version
+pattern ModelModuleVersion = S.SModelModuleVersion
+-- | The model name
 pattern ModelName = S.SModelName
-pattern MsgThrottle = S.SMsgThrottle
-pattern Version = S.SVersion
+-- | A method to be called on display
 pattern DisplayHandler = S.SDisplayHandler
-pattern Visible = S.SVisible
-pattern CSS = S.SCSS
+-- | CSS classes applied to widget DOM element
 pattern DOMClasses = S.SDOMClasses
+-- | Reference to a Layout widget
+pattern Layout = S.SLayout
+-- | Width of the video/image in pixels
 pattern Width = S.SWidth
+-- | Height of the video/image in pixels
 pattern Height = S.SHeight
-pattern Padding = S.SPadding
-pattern Margin = S.SMargin
-pattern Color = S.SColor
-pattern BackgroundColor = S.SBackgroundColor
-pattern BorderColor = S.SBorderColor
-pattern BorderWidth = S.SBorderWidth
-pattern BorderRadius = S.SBorderRadius
-pattern BorderStyle = S.SBorderStyle
-pattern FontStyle = S.SFontStyle
-pattern FontWeight = S.SFontWeight
-pattern FontSize = S.SFontSize
-pattern FontFamily = S.SFontFamily
+-- | Description of the control
 pattern Description = S.SDescription
+-- | Method to be called on click
 pattern ClickHandler = S.SClickHandler
+-- | Method to be called on submit
 pattern SubmitHandler = S.SSubmitHandler
+-- | Whether the widget appears as disabled on the frontend
 pattern Disabled = S.SDisabled
+-- | The value of the widget, of type string
 pattern StringValue = S.SStringValue
+-- | Placeholder text to display if nothing has been typed yet
 pattern Placeholder = S.SPlaceholder
+-- | Tooltip for the description
 pattern Tooltip = S.STooltip
+-- | The font-awesome icon without the fa-
 pattern Icon = S.SIcon
+-- | Predefined styling for the button
 pattern ButtonStyle = S.SButtonStyle
-pattern B64Value = S.SB64Value
+-- | Value of the widget of type bytestring
+pattern BSValue = S.SBSValue
+-- | The format of the image
 pattern ImageFormat = S.SImageFormat
+-- | The value of the widget of type bool
 pattern BoolValue = S.SBoolValue
-pattern Options = S.SOptions
-pattern SelectedLabel = S.SSelectedLabel
-pattern SelectedValue = S.SSelectedValue
+-- | The labels for the options
+pattern OptionsLabels = S.SOptionsLabels
+-- | Selected index, can be Nothing
+pattern OptionalIndex = S.SOptionalIndex
+-- | The index of the controller
+pattern Index = S.SIndex
+-- | Method to be called when something is chosen
 pattern SelectionHandler = S.SSelectionHandler
+-- | Tooltips for each button
 pattern Tooltips = S.STooltips
+-- | Icons names for each button (FontAwesome names without the fa- prefix)
 pattern Icons = S.SIcons
-pattern SelectedLabels = S.SSelectedLabels
-pattern SelectedValues = S.SSelectedValues
+-- | Selected indices
+pattern Indices = S.SIndices
+-- | The value of the widget of type int
 pattern IntValue = S.SIntValue
+-- | Minimum step to increment the value
 pattern StepInt = S.SStepInt
+-- | Max value
 pattern MaxInt = S.SMaxInt
+-- | Min value
 pattern MinInt = S.SMinInt
+-- | The value of the widget as an int pair
 pattern IntPairValue = S.SIntPairValue
+-- | Min value on a range widget
 pattern LowerInt = S.SLowerInt
+-- | Max value on a range widget
 pattern UpperInt = S.SUpperInt
+-- | Value of the widget (float)
 pattern FloatValue = S.SFloatValue
+-- | Minimum step to increment the value
 pattern StepFloat = S.SStepFloat
+-- | Max value
 pattern MaxFloat = S.SMaxFloat
+-- | Min value
 pattern MinFloat = S.SMinFloat
+-- | Value of the widget as a float pair
 pattern FloatPairValue = S.SFloatPairValue
+-- | Min value of a range widget
 pattern LowerFloat = S.SLowerFloat
+-- | Max value of a range widget
 pattern UpperFloat = S.SUpperFloat
+-- | Orientation of the widget
 pattern Orientation = S.SOrientation
-pattern ShowRange = S.SShowRange
+-- | The logarithmic base of the widget
+pattern BaseFloat = S.SBaseFloat
+-- | Whether to display the current value of the widget next to it
 pattern ReadOut = S.SReadOut
-pattern SliderColor = S.SSliderColor
+-- | The format of the readout
+pattern ReadOutFormat = S.SReadOutFormat
+-- | Use a predefined styling for the bar
 pattern BarStyle = S.SBarStyle
+-- | A method called when the value changes in the fronted
 pattern ChangeHandler = S.SChangeHandler
+-- | List of widget children
 pattern Children = S.SChildren
-pattern OverflowX = S.SOverflowX
-pattern OverflowY = S.SOverflowY
+-- | Use a predefined styling for the box
 pattern BoxStyle = S.SBoxStyle
-pattern Flex = S.SFlex
-pattern Pack = S.SPack
-pattern Align = S.SAlign
+-- | Titles of the pages
 pattern Titles = S.STitles
+-- | The index of the selected page. Is nothing if no widgets are selected.
 pattern SelectedIndex = S.SSelectedIndex
+-- | Message displayed when the value is false
 pattern ReadOutMsg = S.SReadOutMsg
-pattern Child = S.SChild
-pattern Selector = S.SSelector
+-- | Indent the control to align with other controls with a description
+pattern Indent = S.SIndent
+-- | Update the value as the user types. If false, update on submission.
+pattern ContinuousUpdate = S.SContinuousUpdate
+-- | The number of rows to display
+pattern Rows = S.SRows
+-- | The format of the audio
+pattern AudioFormat = S.SAudioFormat
+-- | The format of the image
+pattern VideoFormat = S.SVideoFormat
+-- | When true, the video starts on display
+pattern AutoPlay = S.SAutoPlay
+-- | When true, the video starts from the beginning after finishing
+pattern Loop = S.SLoop
+-- | Specifies that video controls should be displayed
+pattern Controls = S.SControls
+-- | Dropdown options for the combobox
+pattern Options = S.SOptions
+-- | If set, ensure the value is in options
+pattern EnsureOption = S.SEnsureOption
+-- | Whether the control is currently playing
+pattern Playing = S.SPlaying
+-- | Whether the control will repeat in a continuous loop
+pattern Repeat = S.SRepeat
+-- | The maximum interval for the play control
+pattern Interval = S.SInterval
+-- | Show the repeat toggle button on the widget
+pattern ShowRepeat = S.SShowRepeat
+-- | Display the short version of the selector
+pattern Concise = S.SConcise
+-- | The value of the widget in date format
+pattern DateValue = S.SDateValue
+-- | Whether the button is pressed
+pattern Pressed = S.SPressed
+-- | The name of the controller
+pattern Name = S.SName
+-- | The name of the control mapping
+pattern Mapping = S.SMapping
+-- | Whether the gamepad is connected
+pattern Connected = S.SConnected
+-- | The last time the data from this gamepad was updated
+pattern Timestamp = S.STimestamp
+-- | The button widgets on the gamepad
+pattern Buttons = S.SButtons
+-- | The axes on the gamepad
+pattern Axes = S.SAxes
+-- | Color of the button
+pattern ButtonColor = S.SButtonColor
+-- | The font weight of the text
+pattern FontWeight = S.SFontWeight
+-- | Width of the description to the side of the control
+pattern DescriptionWidth = S.SDescriptionWidth
+-- | Color of the progress bar
+pattern BarColor = S.SBarColor
+-- | Color of the slider handle
+pattern HandleColor = S.SHandleColor
+-- | The width of each button
+pattern ButtonWidth = S.SButtonWidth
+-- | The target (widget,field) pair
+pattern Target = S.STarget
+-- | The source (widget,field) pair
+pattern Source = S.SSource
+-- | Parent message id of messages to capture
+pattern MsgID = S.SMsgID
+-- | The output messages synced from the frontend
+pattern Outputs = S.SOutputs
+-- | Reference to a Style widget with styling customizations
+pattern Style = S.SStyle
 
 -- | Close a widget's comm
 closeWidget :: IHaskellWidget w => w -> IO ()
 closeWidget w = widgetSendClose w emptyObject
 
+-- | Transforms the Integer to a String of pixels
 newtype PixCount = PixCount Integer
   deriving (Num, Ord, Eq, Enum, Typeable)
 
 instance ToJSON PixCount where
   toJSON (PixCount x) = toJSON . pack $ show x ++ "px"
 
--- | Pre-defined border styles
-data BorderStyleValue = NoBorder
-                      | HiddenBorder
-                      | DottedBorder
-                      | DashedBorder
-                      | SolidBorder
-                      | DoubleBorder
-                      | GrooveBorder
-                      | RidgeBorder
-                      | InsetBorder
-                      | OutsetBorder
-                      | InitialBorder
-                      | InheritBorder
-                      | DefaultBorder
-
-instance ToJSON BorderStyleValue where
-  toJSON NoBorder = "none"
-  toJSON HiddenBorder = "hidden"
-  toJSON DottedBorder = "dotted"
-  toJSON DashedBorder = "dashed"
-  toJSON SolidBorder = "solid"
-  toJSON DoubleBorder = "double"
-  toJSON GrooveBorder = "groove"
-  toJSON RidgeBorder = "ridge"
-  toJSON InsetBorder = "inset"
-  toJSON OutsetBorder = "outset"
-  toJSON InitialBorder = "initial"
-  toJSON InheritBorder = "inherit"
-  toJSON DefaultBorder = ""
-
 -- | Font style values
 data FontStyleValue = NormalFont
                     | ItalicFont
@@ -206,24 +286,53 @@
   toJSON DangerBar = "danger"
   toJSON DefaultBar = ""
 
+-- | Audio formats for AudioWidget
+data AudioFormatValue = MP3
+                      | OGG
+                      | WAV
+                      | AURL
+  deriving (Eq, Typeable)
+
+instance Show AudioFormatValue where
+  show MP3 = "mp3"
+  show OGG = "ogg"
+  show WAV = "wav"
+  show AURL = "url"
+
+instance ToJSON AudioFormatValue where
+  toJSON = toJSON . pack . show
+
 -- | Image formats for ImageWidget
 data ImageFormatValue = PNG
                       | SVG
                       | JPG
+                      | IURL
   deriving (Eq, Typeable)
 
+-- | Image formats for ImageWidget
 instance Show ImageFormatValue where
   show PNG = "png"
   show SVG = "svg"
   show JPG = "jpg"
+  show IURL = "url"
 
 instance ToJSON ImageFormatValue where
   toJSON = toJSON . pack . show
 
--- | Options for selection widgets.
-data SelectionOptions = OptionLabels [Text]
-                      | OptionDict [(Text, Text)]
+-- | Video formats for VideoWidget
+data VideoFormatValue = MP4
+                      | WEBM
+                      | VURL
+  deriving (Eq, Typeable)
 
+instance Show VideoFormatValue where
+  show MP4 = "mp4"
+  show WEBM = "webm"
+  show VURL = "url"
+
+instance ToJSON VideoFormatValue where
+  toJSON = toJSON . pack . show
+
 -- | Orientation values.
 data OrientationValue = HorizontalOrientation
                       | VerticalOrientation
@@ -232,23 +341,7 @@
   toJSON HorizontalOrientation = "horizontal"
   toJSON VerticalOrientation = "vertical"
 
-data OverflowValue = VisibleOverflow
-                   | HiddenOverflow
-                   | ScrollOverflow
-                   | AutoOverflow
-                   | InitialOverflow
-                   | InheritOverflow
-                   | DefaultOverflow
-
-instance ToJSON OverflowValue where
-  toJSON VisibleOverflow = "visible"
-  toJSON HiddenOverflow = "hidden"
-  toJSON ScrollOverflow = "scroll"
-  toJSON AutoOverflow = "auto"
-  toJSON InitialOverflow = "initial"
-  toJSON InheritOverflow = "inherit"
-  toJSON DefaultOverflow = ""
-
+-- | Predefined styles for box widgets
 data BoxStyleValue = SuccessBox
                    | InfoBox
                    | WarningBox
@@ -262,23 +355,15 @@
   toJSON DangerBox = "danger"
   toJSON DefaultBox = ""
 
-data LocationValue = StartLocation
-                   | CenterLocation
-                   | EndLocation
-                   | BaselineLocation
-                   | StretchLocation
-
-instance ToJSON LocationValue where
-  toJSON StartLocation = "start"
-  toJSON CenterLocation = "center"
-  toJSON EndLocation = "end"
-  toJSON BaselineLocation = "baseline"
-  toJSON StretchLocation = "stretch"
-
 -- Could use 'lens-aeson' here but this is easier to read.
+-- | Makes a lookup on a value given a path of strings to follow
 nestedObjectLookup :: Value -> [Text] -> Maybe Value
 nestedObjectLookup val [] = Just val
 nestedObjectLookup val (x:xs) =
   case val of
-    Object o -> maybe Nothing (`nestedObjectLookup` xs) $ HM.lookup x o
+#if MIN_VERSION_aeson(2,0,0)
+    Object o -> (`nestedObjectLookup` xs) =<< KeyMap.lookup (Key.fromText x) o
+#else
+    Object o -> (`nestedObjectLookup` xs) =<< HM.lookup x o
+#endif
     _ -> Nothing
diff --git a/src/IHaskell/Display/Widgets/Controller/Controller.hs b/src/IHaskell/Display/Widgets/Controller/Controller.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Controller/Controller.hs
@@ -0,0 +1,79 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+
+module IHaskell.Display.Widgets.Controller.Controller
+  ( -- * The Controller Widget
+    Controller
+    -- * Constructor
+  , mkController
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Control.Monad (void)
+
+import           Data.Aeson
+import           Data.Aeson.Types (parse)
+import           Data.IORef (newIORef)
+import           Data.Vinyl (Rec(..), (<+>))
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+
+-- | 'Controller' represents an Controller widget from IPython.html.widgets.
+type Controller = IPythonWidget 'ControllerType
+
+-- | Create a new widget
+mkController :: IO Controller
+mkController = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+  layout <- mkLayout
+
+  let domAttrs = defaultCoreWidget <+> defaultDOMWidget "ControllerView" "ControllerModel" layout
+      ctrlAttrs = (Index =:+ 0)
+                  :& (Name =:! "")
+                  :& (Mapping =:! "")
+                  :& (Connected =:! False)
+                  :& (Timestamp =:! 0.0)
+                  :& (Buttons =:! [])
+                  :& (Axes =:! [])
+                  :& (ChangeHandler =:: pure ())
+                  :& RNil
+      widgetState = WidgetState $ domAttrs <+> ctrlAttrs
+
+  stateIO <- newIORef widgetState
+
+  let widget = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen widget $ toJSON widgetState
+
+  -- Return the widget
+  return widget
+
+instance IHaskellWidget Controller where
+  getCommUUID = uuid
+  comm widget val _ =
+    case nestedObjectLookup val ["state"] of
+        Just (Object o) -> do
+            parseAndSet Name "name"
+            parseAndSet Mapping "mapping"
+            parseAndSet Connected "connected"
+            parseAndSet Timestamp "timestamp"
+            triggerChange widget
+            where parseAndSet f s = case parse (.: s) o of
+                    Success x -> void $ setField' widget f x
+                    _ -> pure ()
+        _ -> pure ()
diff --git a/src/IHaskell/Display/Widgets/Controller/ControllerAxis.hs b/src/IHaskell/Display/Widgets/Controller/ControllerAxis.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Controller/ControllerAxis.hs
@@ -0,0 +1,57 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+
+module IHaskell.Display.Widgets.Controller.ControllerAxis
+  ( -- * The ControllerAxis Widget
+    ControllerAxis
+    -- * Constructor
+  , mkControllerAxis
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+import           Data.Vinyl (Rec(..), (<+>))
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+
+-- | 'ControllerAxis' represents an ControllerAxis widget from IPython.html.widgets.
+type ControllerAxis = IPythonWidget 'ControllerAxisType
+
+-- | Create a new widget
+mkControllerAxis :: IO ControllerAxis
+mkControllerAxis = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+  layout <- mkLayout
+
+  let domAttrs = defaultCoreWidget <+> defaultDOMWidget "ControllerAxisView" "ControllerAxisModel" layout
+      axisAttrs = (FloatValue =:! 0.0)
+                  :& (ChangeHandler =:: pure ())
+                  :& RNil
+      widgetState = WidgetState $ domAttrs <+> axisAttrs
+
+  stateIO <- newIORef widgetState
+
+  let widget = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen widget $ toJSON widgetState
+
+  -- Return the widget
+  return widget
+
+instance IHaskellWidget ControllerAxis where
+  getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/Controller/ControllerButton.hs b/src/IHaskell/Display/Widgets/Controller/ControllerButton.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Controller/ControllerButton.hs
@@ -0,0 +1,58 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+
+module IHaskell.Display.Widgets.Controller.ControllerButton
+  ( -- * The ControllerButton Widget
+    ControllerButton
+    -- * Constructor
+  , mkControllerButton
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+import           Data.Vinyl (Rec(..), (<+>))
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+
+-- | 'ControllerButton' represents an ControllerButton widget from IPython.html.widgets.
+type ControllerButton = IPythonWidget 'ControllerButtonType
+
+-- | Create a new widget
+mkControllerButton :: IO ControllerButton
+mkControllerButton = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+  layout <- mkLayout
+
+  let domAttrs = defaultCoreWidget <+> defaultDOMWidget "ControllerButtonView" "ControllerButtonModel" layout
+      btnAttrs = (FloatValue =:! 0.0)
+                 :& (Pressed =:! False)
+                 :& (ChangeHandler =:: pure ())
+                 :& RNil
+      widgetState = WidgetState $ domAttrs <+> btnAttrs
+
+  stateIO <- newIORef widgetState
+
+  let widget = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen widget $ toJSON widgetState
+
+  -- Return the widget
+  return widget
+
+instance IHaskellWidget ControllerButton where
+  getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/DatePicker.hs b/src/IHaskell/Display/Widgets/DatePicker.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/DatePicker.hs
@@ -0,0 +1,66 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+
+module IHaskell.Display.Widgets.DatePicker
+  ( -- * The DatePicker Widget
+    DatePicker
+    -- * Create a new DatePicker
+  , mkDatePicker
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+import           Data.Vinyl (Rec(..), (<+>))
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
+
+-- | A 'DatePicker' represents a DatePicker from IPython.html.widgets.
+type DatePicker = IPythonWidget 'DatePickerType
+
+-- | Create a new DatePicker
+mkDatePicker :: IO DatePicker
+mkDatePicker = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
+
+  let ddw = defaultDescriptionWidget "DatePickerView" "DatePickerModel" layout $ StyleWidget dstyle
+      date = (DateValue =:: defaultDate)
+              :& (Disabled =:: False)
+              :& (ChangeHandler =:: return ())
+              :& RNil
+      datePickerState = WidgetState (ddw <+> date)
+
+  stateIO <- newIORef datePickerState
+
+  let datePicker = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen datePicker $ toJSON datePickerState
+
+  -- Return the DatePicker widget
+  return datePicker
+
+instance IHaskellWidget DatePicker where
+  getCommUUID = uuid
+  comm widget val _ =
+    case nestedObjectLookup val ["state", "value"] of
+      Just o -> case fromJSON o of
+        Success date -> setField' widget DateValue date >> triggerChange widget
+        _ -> pure ()
+      _ -> pure ()
diff --git a/src/IHaskell/Display/Widgets/Float/BoundedFloat/BoundedFloatText.hs b/src/IHaskell/Display/Widgets/Float/BoundedFloat/BoundedFloatText.hs
--- a/src/IHaskell/Display/Widgets/Float/BoundedFloat/BoundedFloatText.hs
+++ b/src/IHaskell/Display/Widgets/Float/BoundedFloat/BoundedFloatText.hs
@@ -19,6 +19,7 @@
 import           Data.Aeson
 import           Data.IORef (newIORef)
 import qualified Data.Scientific as Sci
+import           Data.Vinyl (Rec(..), (<+>))
 
 import           IHaskell.Display
 import           IHaskell.Eval.Widgets
@@ -26,6 +27,8 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | 'BoundedFloatText' represents an BoundedFloatText widget from IPython.html.widgets.
 type BoundedFloatText = IPythonWidget 'BoundedFloatTextType
@@ -35,8 +38,15 @@
 mkBoundedFloatText = do
   -- Default properties, with a random uuid
   wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
-  let widgetState = WidgetState $ defaultBoundedFloatWidget "FloatTextView" "FloatTextModel"
+  let boundedFloatAttrs = defaultBoundedFloatWidget "FloatTextView" "BoundedFloatTextModel" layout $ StyleWidget dstyle
+      textAttrs = (Disabled =:: False)
+                  :& (ContinuousUpdate =:: False)
+                  :& (StepFloat =:: Nothing)
+                  :& RNil
+      widgetState = WidgetState $ boundedFloatAttrs <+> textAttrs
 
   stateIO <- newIORef widgetState
 
@@ -48,15 +58,10 @@
   -- Return the widget
   return widget
 
-instance IHaskellDisplay BoundedFloatText where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget BoundedFloatText where
   getCommUUID = uuid
   comm widget val _ =
-    case nestedObjectLookup val ["sync_data", "value"] of
+    case nestedObjectLookup val ["state", "value"] of
       Just (Number value) -> do
         void $ setField' widget FloatValue (Sci.toRealFloat value)
         triggerChange widget
diff --git a/src/IHaskell/Display/Widgets/Float/BoundedFloat/FloatLogSlider.hs b/src/IHaskell/Display/Widgets/Float/BoundedFloat/FloatLogSlider.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Float/BoundedFloat/FloatLogSlider.hs
@@ -0,0 +1,72 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+
+module IHaskell.Display.Widgets.Float.BoundedFloat.FloatLogSlider
+  ( -- * The FloatSlider Widget
+    FloatLogSlider
+    -- * Constructor
+  , mkFloatLogSlider
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Control.Monad (void)
+import           Data.Aeson
+import           Data.IORef (newIORef)
+import qualified Data.Scientific as Sci
+import           Data.Vinyl (Rec(..), (<+>))
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
+
+-- | 'FloatLogSlider' represents an FloatLogSlider widget from IPython.html.widgets.
+type FloatLogSlider = IPythonWidget 'FloatLogSliderType
+
+-- | Create a new widget
+mkFloatLogSlider :: IO FloatLogSlider
+mkFloatLogSlider = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
+
+  let boundedLogFloatAttrs = defaultBoundedLogFloatWidget "FloatLogSliderView" "FloatLogSliderModel" layout $ StyleWidget dstyle
+      sliderAttrs = (StepFloat =:: Just 0.1)
+                    :& (Orientation =:: HorizontalOrientation)
+                    :& (ReadOut =:: True)
+                    :& (ReadOutFormat =:: ".3g")
+                    :& (ContinuousUpdate =:: True)
+                    :& (Disabled =:: False)
+                    :& (BaseFloat =:: 10.0)
+                    :& RNil
+      widgetState = WidgetState $ boundedLogFloatAttrs <+> sliderAttrs
+
+  stateIO <- newIORef widgetState
+
+  let widget = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen widget $ toJSON widgetState
+
+  -- Return the widget
+  return widget
+
+instance IHaskellWidget FloatLogSlider where
+  getCommUUID = uuid
+  comm widget val _ =
+    case nestedObjectLookup val ["state", "value"] of
+      Just (Number value) -> do
+        void $ setField' widget FloatValue (Sci.toRealFloat value)
+        triggerChange widget
+      _ -> pure ()
diff --git a/src/IHaskell/Display/Widgets/Float/BoundedFloat/FloatProgress.hs b/src/IHaskell/Display/Widgets/Float/BoundedFloat/FloatProgress.hs
--- a/src/IHaskell/Display/Widgets/Float/BoundedFloat/FloatProgress.hs
+++ b/src/IHaskell/Display/Widgets/Float/BoundedFloat/FloatProgress.hs
@@ -25,6 +25,8 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.ProgressStyle
 
 -- | 'FloatProgress' represents an FloatProgress widget from IPython.html.widgets.
 type FloatProgress = IPythonWidget 'FloatProgressType
@@ -34,8 +36,10 @@
 mkFloatProgress = do
   -- Default properties, with a random uuid
   wid <- U.random
+  layout <- mkLayout
+  pstyle <- mkProgressStyle
 
-  let boundedFloatAttrs = defaultBoundedFloatWidget "ProgressView" "ProgressModel"
+  let boundedFloatAttrs = defaultBoundedFloatWidget "ProgressView" "FloatProgressModel" layout $ StyleWidget pstyle
       progressAttrs = (Orientation =:: HorizontalOrientation)
                       :& (BarStyle =:: DefaultBar)
                       :& RNil
@@ -50,11 +54,6 @@
 
   -- Return the widget
   return widget
-
-instance IHaskellDisplay FloatProgress where
-  display b = do
-    widgetSendView b
-    return $ Display []
 
 instance IHaskellWidget FloatProgress where
   getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/Float/BoundedFloat/FloatSlider.hs b/src/IHaskell/Display/Widgets/Float/BoundedFloat/FloatSlider.hs
--- a/src/IHaskell/Display/Widgets/Float/BoundedFloat/FloatSlider.hs
+++ b/src/IHaskell/Display/Widgets/Float/BoundedFloat/FloatSlider.hs
@@ -27,6 +27,8 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | 'FloatSlider' represents an FloatSlider widget from IPython.html.widgets.
 type FloatSlider = IPythonWidget 'FloatSliderType
@@ -36,12 +38,16 @@
 mkFloatSlider = do
   -- Default properties, with a random uuid
   wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
-  let boundedFloatAttrs = defaultBoundedFloatWidget "FloatSliderView" "FloatSliderModel"
-      sliderAttrs = (Orientation =:: HorizontalOrientation)
-                    :& (ShowRange =:: False)
+  let boundedFloatAttrs = defaultBoundedFloatWidget "FloatSliderView" "FloatSliderModel" layout $ StyleWidget dstyle
+      sliderAttrs = (StepFloat =:: Just 0.1)
+                    :& (Orientation =:: HorizontalOrientation)
                     :& (ReadOut =:: True)
-                    :& (SliderColor =:: "")
+                    :& (ReadOutFormat =:: ".2f")
+                    :& (ContinuousUpdate =:: True)
+                    :& (Disabled =:: False)
                     :& RNil
       widgetState = WidgetState $ boundedFloatAttrs <+> sliderAttrs
 
@@ -55,15 +61,10 @@
   -- Return the widget
   return widget
 
-instance IHaskellDisplay FloatSlider where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget FloatSlider where
   getCommUUID = uuid
   comm widget val _ =
-    case nestedObjectLookup val ["sync_data", "value"] of
+    case nestedObjectLookup val ["state", "value"] of
       Just (Number value) -> do
         void $ setField' widget FloatValue (Sci.toRealFloat value)
         triggerChange widget
diff --git a/src/IHaskell/Display/Widgets/Float/BoundedFloatRange/FloatRangeSlider.hs b/src/IHaskell/Display/Widgets/Float/BoundedFloatRange/FloatRangeSlider.hs
--- a/src/IHaskell/Display/Widgets/Float/BoundedFloatRange/FloatRangeSlider.hs
+++ b/src/IHaskell/Display/Widgets/Float/BoundedFloatRange/FloatRangeSlider.hs
@@ -28,6 +28,8 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | 'FloatRangeSlider' represents an FloatRangeSlider widget from IPython.html.widgets.
 type FloatRangeSlider = IPythonWidget 'FloatRangeSliderType
@@ -37,12 +39,16 @@
 mkFloatRangeSlider = do
   -- Default properties, with a random uuid
   wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
-  let boundedFloatAttrs = defaultBoundedFloatRangeWidget "FloatSliderView" "FloatSliderModel"
-      sliderAttrs = (Orientation =:: HorizontalOrientation)
-                    :& (ShowRange =:: True)
+  let boundedFloatAttrs = defaultBoundedFloatRangeWidget "FloatRangeSliderView" "FloatRangeSliderModel" layout $ StyleWidget dstyle
+      sliderAttrs = (StepFloat =:: Just 0.1)
+                    :& (Orientation =:: HorizontalOrientation)
                     :& (ReadOut =:: True)
-                    :& (SliderColor =:: "")
+                    :& (ReadOutFormat =:: ".2f")
+                    :& (ContinuousUpdate =:: True)
+                    :& (Disabled =:: False)
                     :& RNil
       widgetState = WidgetState $ boundedFloatAttrs <+> sliderAttrs
 
@@ -56,15 +62,10 @@
   -- Return the widget
   return widget
 
-instance IHaskellDisplay FloatRangeSlider where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget FloatRangeSlider where
   getCommUUID = uuid
   comm widget val _ =
-    case nestedObjectLookup val ["sync_data", "value"] of
+    case nestedObjectLookup val ["state", "value"] of
       Just (Array values) ->
         case map (\(Number x) -> Sci.toRealFloat x) $ V.toList values of
           [x, y] -> do
diff --git a/src/IHaskell/Display/Widgets/Float/FloatText.hs b/src/IHaskell/Display/Widgets/Float/FloatText.hs
--- a/src/IHaskell/Display/Widgets/Float/FloatText.hs
+++ b/src/IHaskell/Display/Widgets/Float/FloatText.hs
@@ -19,6 +19,7 @@
 import           Data.Aeson
 import           Data.IORef (newIORef)
 import qualified Data.Scientific as Sci
+import           Data.Vinyl (Rec(..), (<+>))
 
 import           IHaskell.Display
 import           IHaskell.Eval.Widgets
@@ -26,6 +27,8 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | 'FloatText' represents an FloatText widget from IPython.html.widgets.
 type FloatText = IPythonWidget 'FloatTextType
@@ -35,8 +38,15 @@
 mkFloatText = do
   -- Default properties, with a random uuid
   wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
-  let widgetState = WidgetState $ defaultFloatWidget "FloatTextView" "FloatTextModel"
+  let floatAttrs = defaultFloatWidget "FloatTextView" "FloatTextModel" layout $ StyleWidget dstyle
+      textAttrs = (Disabled =:: False)
+                  :& (ContinuousUpdate =:: False)
+                  :& (StepFloat =:: Nothing)
+                  :& RNil
+      widgetState = WidgetState $ floatAttrs <+> textAttrs
 
   stateIO <- newIORef widgetState
 
@@ -48,15 +58,10 @@
   -- Return the widget
   return widget
 
-instance IHaskellDisplay FloatText where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget FloatText where
   getCommUUID = uuid
   comm widget val _ =
-    case nestedObjectLookup val ["sync_data", "value"] of
+    case nestedObjectLookup val ["state", "value"] of
       Just (Number value) -> do
         void $ setField' widget FloatValue (Sci.toRealFloat value)
         triggerChange widget
diff --git a/src/IHaskell/Display/Widgets/Image.hs b/src/IHaskell/Display/Widgets/Image.hs
deleted file mode 100644
--- a/src/IHaskell/Display/Widgets/Image.hs
+++ /dev/null
@@ -1,63 +0,0 @@
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE DataKinds #-}
-{-# LANGUAGE TypeSynonymInstances #-}
-
-{-# OPTIONS_GHC -fno-warn-orphans #-}
-
-module IHaskell.Display.Widgets.Image
-  ( -- * The Image Widget
-    ImageWidget
-    -- * Constructor
-  , mkImageWidget
-  ) where
-
--- To keep `cabal repl` happy when running from the ihaskell repo
-import           Prelude
-
-import           Data.Aeson
-import           Data.IORef (newIORef)
-import           Data.Monoid (mempty)
-import           Data.Vinyl (Rec(..), (<+>))
-
-import           IHaskell.Display
-import           IHaskell.Eval.Widgets
-import           IHaskell.IPython.Message.UUID as U
-
-import           IHaskell.Display.Widgets.Types
-import           IHaskell.Display.Widgets.Common
-
--- | An 'ImageWidget' represents a Image widget from IPython.html.widgets.
-type ImageWidget = IPythonWidget 'ImageType
-
--- | Create a new image widget
-mkImageWidget :: IO ImageWidget
-mkImageWidget = do
-  -- Default properties, with a random uuid
-  wid <- U.random
-
-  let dom = defaultDOMWidget "ImageView" "ImageModel"
-      img = (ImageFormat =:: PNG)
-            :& (Width =:+ 0)
-            :& (Height =:+ 0)
-            :& (B64Value =:: mempty)
-            :& RNil
-      widgetState = WidgetState (dom <+> img)
-
-  stateIO <- newIORef widgetState
-
-  let widget = IPythonWidget wid stateIO
-
-  -- Open a comm for this widget, and store it in the kernel state
-  widgetSendOpen widget $ toJSON widgetState
-
-  -- Return the image widget
-  return widget
-
-instance IHaskellDisplay ImageWidget where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
-instance IHaskellWidget ImageWidget where
-  getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/Int/BoundedInt/BoundedIntText.hs b/src/IHaskell/Display/Widgets/Int/BoundedInt/BoundedIntText.hs
--- a/src/IHaskell/Display/Widgets/Int/BoundedInt/BoundedIntText.hs
+++ b/src/IHaskell/Display/Widgets/Int/BoundedInt/BoundedIntText.hs
@@ -19,6 +19,7 @@
 import           Data.Aeson
 import           Data.IORef (newIORef)
 import qualified Data.Scientific as Sci
+import           Data.Vinyl (Rec(..), (<+>))
 
 import           IHaskell.Display
 import           IHaskell.Eval.Widgets
@@ -26,6 +27,8 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | 'BoundedIntText' represents an BoundedIntText widget from IPython.html.widgets.
 type BoundedIntText = IPythonWidget 'BoundedIntTextType
@@ -35,8 +38,15 @@
 mkBoundedIntText = do
   -- Default properties, with a random uuid
   wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
-  let widgetState = WidgetState $ defaultBoundedIntWidget "IntTextView" "IntTextModel"
+  let boundedIntAttrs = defaultBoundedIntWidget "IntTextView" "BoundedIntTextModel" layout $ StyleWidget dstyle
+      textAttrs = (Disabled =:: False)
+                  :& (ContinuousUpdate =:: False)
+                  :& (StepInt =:: Just 1)
+                  :& RNil
+      widgetState = WidgetState $ boundedIntAttrs <+> textAttrs
 
   stateIO <- newIORef widgetState
 
@@ -48,15 +58,10 @@
   -- Return the widget
   return widget
 
-instance IHaskellDisplay BoundedIntText where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget BoundedIntText where
   getCommUUID = uuid
   comm widget val _ =
-    case nestedObjectLookup val ["sync_data", "value"] of
+    case nestedObjectLookup val ["state", "value"] of
       Just (Number value) -> do
         void $ setField' widget IntValue (Sci.coefficient value)
         triggerChange widget
diff --git a/src/IHaskell/Display/Widgets/Int/BoundedInt/IntProgress.hs b/src/IHaskell/Display/Widgets/Int/BoundedInt/IntProgress.hs
--- a/src/IHaskell/Display/Widgets/Int/BoundedInt/IntProgress.hs
+++ b/src/IHaskell/Display/Widgets/Int/BoundedInt/IntProgress.hs
@@ -25,6 +25,8 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | 'IntProgress' represents an IntProgress widget from IPython.html.widgets.
 type IntProgress = IPythonWidget 'IntProgressType
@@ -34,8 +36,10 @@
 mkIntProgress = do
   -- Default properties, with a random uuid
   wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
-  let boundedIntAttrs = defaultBoundedIntWidget "ProgressView" "ProgressModel"
+  let boundedIntAttrs = defaultBoundedIntWidget "ProgressView" "IntProgressModel" layout $ StyleWidget dstyle
       progressAttrs = (Orientation =:: HorizontalOrientation)
                       :& (BarStyle =:: DefaultBar)
                       :& RNil
@@ -50,11 +54,6 @@
 
   -- Return the widget
   return widget
-
-instance IHaskellDisplay IntProgress where
-  display b = do
-    widgetSendView b
-    return $ Display []
 
 instance IHaskellWidget IntProgress where
   getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/Int/BoundedInt/IntSlider.hs b/src/IHaskell/Display/Widgets/Int/BoundedInt/IntSlider.hs
--- a/src/IHaskell/Display/Widgets/Int/BoundedInt/IntSlider.hs
+++ b/src/IHaskell/Display/Widgets/Int/BoundedInt/IntSlider.hs
@@ -21,12 +21,14 @@
 import qualified Data.Scientific as Sci
 import           Data.Vinyl (Rec(..), (<+>))
 
-import           IHaskell.Display
 import           IHaskell.Eval.Widgets
 import           IHaskell.IPython.Message.UUID as U
 
+import           IHaskell.Display (IHaskellWidget(..))
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | 'IntSlider' represents an IntSlider widget from IPython.html.widgets.
 type IntSlider = IPythonWidget 'IntSliderType
@@ -36,12 +38,16 @@
 mkIntSlider = do
   -- Default properties, with a random uuid
   wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
-  let boundedIntAttrs = defaultBoundedIntWidget "IntSliderView" "IntSliderModel"
-      sliderAttrs = (Orientation =:: HorizontalOrientation)
-                    :& (ShowRange =:: False)
+  let boundedIntAttrs = defaultBoundedIntWidget "IntSliderView" "IntSliderModel" layout $ StyleWidget dstyle
+      sliderAttrs = (StepInt =:: Just 1)
+                    :& (Orientation =:: HorizontalOrientation)
                     :& (ReadOut =:: True)
-                    :& (SliderColor =:: "")
+                    :& (ReadOutFormat =:: "d")
+                    :& (ContinuousUpdate =:: True)
+                    :& (Disabled =:: False)
                     :& RNil
       widgetState = WidgetState $ boundedIntAttrs <+> sliderAttrs
 
@@ -55,15 +61,10 @@
   -- Return the widget
   return widget
 
-instance IHaskellDisplay IntSlider where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget IntSlider where
   getCommUUID = uuid
   comm widget val _ =
-    case nestedObjectLookup val ["sync_data", "value"] of
+    case nestedObjectLookup val ["state", "value"] of
       Just (Number value) -> do
         void $ setField' widget IntValue (Sci.coefficient value)
         triggerChange widget
diff --git a/src/IHaskell/Display/Widgets/Int/BoundedInt/Play.hs b/src/IHaskell/Display/Widgets/Int/BoundedInt/Play.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Int/BoundedInt/Play.hs
@@ -0,0 +1,71 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+
+module IHaskell.Display.Widgets.Int.BoundedInt.Play
+  ( -- * The Play Widget
+    Play
+    -- * Constructor
+  , mkPlay
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Control.Monad (void)
+import           Data.Aeson
+import           Data.IORef (newIORef)
+import qualified Data.Scientific as Sci
+import           Data.Vinyl (Rec(..), (<+>))
+
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display (IHaskellWidget(..))
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
+
+-- | 'Play' represents an Play widget from IPython.html.widgets.
+type Play = IPythonWidget 'PlayType
+
+-- | Create a new widget
+mkPlay :: IO Play
+mkPlay = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
+
+  let boundedIntAttrs = defaultBoundedIntWidget "PlayView" "PlayModel" layout $ StyleWidget dstyle
+      playAttrs = (Playing =:: True)
+                  :& (Repeat =:: True)
+                  :& (Interval =:: 100)
+                  :& (StepInt =:: Just 1)
+                  :& (Disabled =:: False)
+                  :& (ShowRepeat =:: True)
+                  :& RNil
+      widgetState = WidgetState $ boundedIntAttrs <+> playAttrs
+
+  stateIO <- newIORef widgetState
+
+  let widget = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen widget $ toJSON widgetState
+
+  -- Return the widget
+  return widget
+
+instance IHaskellWidget Play where
+  getCommUUID = uuid
+  comm widget val _ =
+    case nestedObjectLookup val ["state", "value"] of
+      Just (Number value) -> do
+        void $ setField' widget IntValue (Sci.coefficient value)
+        triggerChange widget
+      _ -> pure ()
diff --git a/src/IHaskell/Display/Widgets/Int/BoundedIntRange/IntRangeSlider.hs b/src/IHaskell/Display/Widgets/Int/BoundedIntRange/IntRangeSlider.hs
--- a/src/IHaskell/Display/Widgets/Int/BoundedIntRange/IntRangeSlider.hs
+++ b/src/IHaskell/Display/Widgets/Int/BoundedIntRange/IntRangeSlider.hs
@@ -28,6 +28,8 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | 'IntRangeSlider' represents an IntRangeSlider widget from IPython.html.widgets.
 type IntRangeSlider = IPythonWidget 'IntRangeSliderType
@@ -37,12 +39,16 @@
 mkIntRangeSlider = do
   -- Default properties, with a random uuid
   wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
-  let boundedIntAttrs = defaultBoundedIntRangeWidget "IntSliderView" "IntSliderModel"
-      sliderAttrs = (Orientation =:: HorizontalOrientation)
-                    :& (ShowRange =:: True)
+  let boundedIntAttrs = defaultBoundedIntRangeWidget "IntRangeSliderView" "IntRangeSliderModel" layout $ StyleWidget dstyle
+      sliderAttrs = (StepInt =:: Just 1)
+                    :& (Orientation =:: HorizontalOrientation)
                     :& (ReadOut =:: True)
-                    :& (SliderColor =:: "")
+                    :& (ReadOutFormat =:: "d")
+                    :& (ContinuousUpdate =:: True)
+                    :& (Disabled =:: False)
                     :& RNil
       widgetState = WidgetState $ boundedIntAttrs <+> sliderAttrs
 
@@ -56,15 +62,10 @@
   -- Return the widget
   return widget
 
-instance IHaskellDisplay IntRangeSlider where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget IntRangeSlider where
   getCommUUID = uuid
   comm widget val _ =
-    case nestedObjectLookup val ["sync_data", "value"] of
+    case nestedObjectLookup val ["state", "value"] of
       Just (Array values) ->
         case map (\(Number x) -> Sci.coefficient x) $ V.toList values of
           [x, y] -> do
diff --git a/src/IHaskell/Display/Widgets/Int/IntText.hs b/src/IHaskell/Display/Widgets/Int/IntText.hs
--- a/src/IHaskell/Display/Widgets/Int/IntText.hs
+++ b/src/IHaskell/Display/Widgets/Int/IntText.hs
@@ -19,6 +19,7 @@
 import           Data.Aeson
 import           Data.IORef (newIORef)
 import qualified Data.Scientific as Sci
+import           Data.Vinyl (Rec(..), (<+>))
 
 import           IHaskell.Display
 import           IHaskell.Eval.Widgets
@@ -26,6 +27,8 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | 'IntText' represents an IntText widget from IPython.html.widgets.
 type IntText = IPythonWidget 'IntTextType
@@ -35,8 +38,15 @@
 mkIntText = do
   -- Default properties, with a random uuid
   wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
-  let widgetState = WidgetState $ defaultIntWidget "IntTextView" "IntTextModel"
+  let intAttrs = defaultIntWidget "IntTextView" "IntTextModel" layout $ StyleWidget dstyle
+      textAttrs = (Disabled =:: False)
+                  :& (ContinuousUpdate =:: False)
+                  :& (StepInt =:: Just 1)
+                  :& RNil
+      widgetState = WidgetState $ intAttrs <+> textAttrs
 
   stateIO <- newIORef widgetState
 
@@ -48,15 +58,10 @@
   -- Return the widget
   return widget
 
-instance IHaskellDisplay IntText where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget IntText where
   getCommUUID = uuid
   comm widget val _ =
-    case nestedObjectLookup val ["sync_data", "value"] of
+    case nestedObjectLookup val ["state", "value"] of
       Just (Number value) -> do
         void $ setField' widget IntValue (Sci.coefficient value)
         triggerChange widget
diff --git a/src/IHaskell/Display/Widgets/Interactive.hs b/src/IHaskell/Display/Widgets/Interactive.hs
--- a/src/IHaskell/Display/Widgets/Interactive.hs
+++ b/src/IHaskell/Display/Widgets/Interactive.hs
@@ -148,7 +148,7 @@
       initializers = rmap extractInitializer rc
 
   bx <- mkBox
-  out <- mkOutputWidget
+  out <- mkOutput
 
   -- Create a list of widgets
   widgets <- rtraverse createWidget constructors
@@ -163,7 +163,7 @@
   -- Set initial values for all widgets
   setInitialValues initializers widgets initvals
   -- applyValueSetters valueSetters widgets $ getList defvals
-  setField out Width 500
+  -- setField out Width 500
   -- TODO This can't be set right now since we switched FlexBox to a regular
   --      Box. This is a styling/layout parameter now but these haven't been implemented yet.
   -- setField bx Orientation VerticalOrientation
@@ -214,7 +214,7 @@
   type SuitableField Text = 'S.StringValue
   data Argument Text = TextVal Text
   initializer w (TextVal txt) = setField w StringValue txt
-  wrapped = WrappedWidget mkTextWidget SubmitHandler StringValue
+  wrapped = WrappedWidget mkText SubmitHandler StringValue
 
 instance FromWidget Integer where
   type SuitableWidget Integer = 'IntSliderType
diff --git a/src/IHaskell/Display/Widgets/Layout.hs b/src/IHaskell/Display/Widgets/Layout.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Layout.hs
@@ -0,0 +1,5 @@
+module IHaskell.Display.Widgets.Layout (module X) where
+
+import IHaskell.Display.Widgets.Layout.Common as X
+import IHaskell.Display.Widgets.Layout.Types as X
+import IHaskell.Display.Widgets.Layout.LayoutWidget as X
diff --git a/src/IHaskell/Display/Widgets/Layout/Common.hs b/src/IHaskell/Display/Widgets/Layout/Common.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Layout/Common.hs
@@ -0,0 +1,70 @@
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE AutoDeriveTypeable #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+
+-- There are lots of pattern synpnyms, and little would be gained by adding
+-- the type signatures.
+{-# OPTIONS_GHC -fno-warn-missing-pattern-synonym-signatures #-}
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+
+module IHaskell.Display.Widgets.Layout.Common where
+
+import qualified IHaskell.Display.Widgets.Singletons as S
+
+pattern AlignContent = S.SLAlignContent
+pattern AlignItems = S.SLAlignItems
+pattern AlignSelf = S.SLAlignSelf
+pattern Border = S.SLBorder
+pattern Bottom = S.SLBottom
+pattern Display = S.SLDisplay
+pattern Flex = S.SLFlex
+pattern FlexFlow = S.SLFlexFlow
+pattern GridArea = S.SLGridArea
+pattern GridAutoColumns = S.SLGridAutoColumns
+pattern GridAutoFlow = S.SLGridAutoFlow
+pattern GridAutoRows = S.SLGridAutoRows
+pattern GridColumn = S.SLGridColumn
+pattern GridGap = S.SLGridGap
+pattern GridRow = S.SLGridRow
+pattern GridTemplateAreas = S.SLGridTemplateAreas
+pattern GridTemplateColumns = S.SLGridTemplateColumns
+pattern GridTemplateRows = S.SLGridTemplateRows
+pattern Height = S.SLHeight
+pattern JustifyContent = S.SLJustifyContent
+pattern JustifyItems = S.SLJustifyItems
+pattern Left = S.SLLeft
+pattern Margin = S.SLMargin
+pattern MaxHeight = S.SLMaxHeight
+pattern MaxWidth = S.SLMaxWidth
+pattern MinHeight = S.SLMinHeight
+pattern MinWidth = S.SLMinWidth
+pattern Order = S.SLOrder
+pattern Overflow = S.SLOverflow
+pattern OverflowX = S.SLOverflowX
+pattern OverflowY = S.SLOverflowY
+pattern Padding = S.SLPadding
+pattern Right = S.SLRight
+pattern Top = S.SLTop
+pattern Visibility = S.SLVisibility
+pattern Width = S.SLWidth
+
+-- TODO: This should be implemented with static type checking, so it's
+-- easier to verify at compile-time. "The Haskell Way".
+-- But a lot of these fields have common values. ¿Maybe doing some kind
+-- of singleton for the CSS fields? ¿Maybe appending the type like
+-- InheritOverflow / InheritVisible / InheritGrid...
+-- In the meantime we'll use arrays of strings and some runtime verification
+cssProps :: [String]
+cssProps = ["inherit", "initial", "unset"]
+alignContentProps = ["flex-start", "flex-end", "center", "space-between", "space-around", "space-evenly", "stretch"] ++ cssProps
+alignItemProps =  ["flex-start", "flex-end", "center", "baseline", "stretch"] ++ cssProps
+alignSelfProps = ["auto", "flex-start", "flex-end", "center", "baseline", "stretch"] ++ cssProps
+gridAutoFlowProps = ["column", "row", "row dense", "column dense"] ++ cssProps
+justifyContentProps = ["flex-start", "flex-end", "center", "space-between", "space-around"] ++ cssProps
+justifyItemsProps = ["flex-start", "flex-end", "center"] ++ cssProps
+overflowProps = ["visible", "hidden", "scroll", "auto"] ++ cssProps
+visibilityProps = ["visible", "hidden"] ++ cssProps
diff --git a/src/IHaskell/Display/Widgets/Layout/LayoutWidget.hs b/src/IHaskell/Display/Widgets/Layout/LayoutWidget.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Layout/LayoutWidget.hs
@@ -0,0 +1,50 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+
+module IHaskell.Display.Widgets.Layout.LayoutWidget
+  ( -- * The Layout Widget
+    Layout
+    -- * Create a new Layout
+  , mkLayout
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Layout.Types
+
+-- | A 'Layout' represents a Layout from IPython.html.widgets.
+type Layout = IPythonWidget 'LayoutType
+
+-- | Create a new Layout
+mkLayout :: IO Layout
+mkLayout = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+
+  let layoutState = WidgetState defaultLayoutWidget
+
+  stateIO <- newIORef layoutState
+
+  let layout = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen layout $ toJSON layoutState
+
+  -- Return the Layout widget
+  return layout
+
+instance IHaskellWidget Layout where
+  getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/Layout/Types.hs b/src/IHaskell/Display/Widgets/Layout/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Layout/Types.hs
@@ -0,0 +1,169 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE AutoDeriveTypeable #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE FlexibleContexts #-}
+
+module IHaskell.Display.Widgets.Layout.Types where
+
+import           Prelude hiding (Right,Left)
+
+import           Control.Monad (unless)
+import qualified Control.Exception as Ex
+
+import           Data.List (intercalate)
+
+import           Data.Vinyl (Rec(..))
+
+import qualified IHaskell.Display.Widgets.Singletons as S
+import           IHaskell.Display.Widgets.Types
+
+import           IHaskell.Display.Widgets.Layout.Common
+
+type LayoutClass = [ 'S.ModelModule
+                   , 'S.ModelModuleVersion
+                   , 'S.ModelName
+                   , 'S.ViewModule
+                   , 'S.ViewModuleVersion
+                   , 'S.ViewName
+                   , 'S.LAlignContent
+                   , 'S.LAlignItems
+                   , 'S.LAlignSelf
+                   , 'S.LBorder
+                   , 'S.LBottom
+                   , 'S.LDisplay
+                   , 'S.LFlex
+                   , 'S.LFlexFlow
+                   , 'S.LGridArea
+                   , 'S.LGridAutoColumns
+                   , 'S.LGridAutoFlow
+                   , 'S.LGridAutoRows
+                   , 'S.LGridColumn
+                   , 'S.LGridGap
+                   , 'S.LGridRow
+                   , 'S.LGridTemplateAreas
+                   , 'S.LGridTemplateColumns
+                   , 'S.LGridTemplateRows
+                   , 'S.LHeight
+                   , 'S.LJustifyContent
+                   , 'S.LJustifyItems
+                   , 'S.LLeft
+                   , 'S.LMargin
+                   , 'S.LMaxHeight
+                   , 'S.LMaxWidth
+                   , 'S.LMinHeight
+                   , 'S.LMinWidth
+                   , 'S.LOrder
+                   , 'S.LOverflow
+                   , 'S.LOverflowX
+                   , 'S.LOverflowY
+                   , 'S.LPadding
+                   , 'S.LRight
+                   , 'S.LTop
+                   , 'S.LVisibility
+                   , 'S.LWidth
+                   ]
+
+type instance FieldType 'S.LAlignContent = Maybe String
+type instance FieldType 'S.LAlignItems = Maybe String
+type instance FieldType 'S.LAlignSelf = Maybe String
+type instance FieldType 'S.LBorder = Maybe String
+type instance FieldType 'S.LBottom = Maybe String
+type instance FieldType 'S.LDisplay = Maybe String
+type instance FieldType 'S.LFlex = Maybe String
+type instance FieldType 'S.LFlexFlow = Maybe String
+type instance FieldType 'S.LGridArea = Maybe String
+type instance FieldType 'S.LGridAutoColumns = Maybe String
+type instance FieldType 'S.LGridAutoFlow = Maybe String
+type instance FieldType 'S.LGridAutoRows = Maybe String
+type instance FieldType 'S.LGridColumn = Maybe String
+type instance FieldType 'S.LGridGap = Maybe String
+type instance FieldType 'S.LGridRow = Maybe String
+type instance FieldType 'S.LGridTemplateAreas = Maybe String
+type instance FieldType 'S.LGridTemplateColumns = Maybe String
+type instance FieldType 'S.LGridTemplateRows = Maybe String
+type instance FieldType 'S.LHeight = Maybe String
+type instance FieldType 'S.LJustifyContent = Maybe String
+type instance FieldType 'S.LJustifyItems = Maybe String
+type instance FieldType 'S.LLeft = Maybe String
+type instance FieldType 'S.LMargin = Maybe String
+type instance FieldType 'S.LMaxHeight = Maybe String
+type instance FieldType 'S.LMaxWidth = Maybe String
+type instance FieldType 'S.LMinHeight = Maybe String
+type instance FieldType 'S.LMinWidth = Maybe String
+type instance FieldType 'S.LOrder = Maybe String
+type instance FieldType 'S.LOverflow = Maybe String
+type instance FieldType 'S.LOverflowX = Maybe String
+type instance FieldType 'S.LOverflowY = Maybe String
+type instance FieldType 'S.LPadding = Maybe String
+type instance FieldType 'S.LRight = Maybe String
+type instance FieldType 'S.LTop = Maybe String
+type instance FieldType 'S.LVisibility = Maybe String
+type instance FieldType 'S.LWidth = Maybe String
+
+-- type family WidgetFields (w :: WidgetType) :: [Field] where
+type instance WidgetFields 'LayoutType = LayoutClass
+
+-- | A record representing a widget of the Layour class from IPython
+defaultLayoutWidget :: Rec Attr LayoutClass
+defaultLayoutWidget = (S.SModelModule =:! "@jupyter-widgets/base")
+                      :& (S.SModelModuleVersion =:! "1.1.0")
+                      :& (S.SModelName =:! "LayoutModel")
+                      :& (S.SViewModule =:! "@jupyter-widgets/base")
+                      :& (S.SViewModuleVersion =:! "1.1.0")
+                      :& (S.SViewName =:! "LayoutView")
+                      :& (AlignContent =:. (Nothing, venum alignContentProps))
+                      :& (AlignItems =:. (Nothing, venum alignItemProps))
+                      :& (AlignSelf =:. (Nothing, venum alignSelfProps))
+                      :& (Border =:: Nothing)
+                      :& (Bottom =:: Nothing)
+                      :& (Display =:: Nothing)
+                      :& (Flex =:: Nothing)
+                      :& (FlexFlow =:: Nothing)
+                      :& (GridArea =:: Nothing)
+                      :& (GridAutoColumns =:: Nothing)
+                      :& (GridAutoFlow =:. (Nothing, venum gridAutoFlowProps))
+                      :& (GridAutoRows =:: Nothing)
+                      :& (GridColumn =:: Nothing)
+                      :& (GridGap =:: Nothing)
+                      :& (GridRow =:: Nothing)
+                      :& (GridTemplateAreas =:: Nothing)
+                      :& (GridTemplateColumns =:: Nothing)
+                      :& (GridTemplateRows =:: Nothing)
+                      :& (Height =:: Nothing)
+                      :& (JustifyContent =:: Nothing)
+                      :& (JustifyItems =:: Nothing)
+                      :& (Left =:: Nothing)
+                      :& (Margin =:: Nothing)
+                      :& (MaxHeight =:: Nothing)
+                      :& (MaxWidth =:: Nothing)
+                      :& (MinHeight =:: Nothing)
+                      :& (MinWidth =:: Nothing)
+                      :& (Order =:: Nothing)
+                      :& (Overflow =:. (Nothing, venum overflowProps))
+                      :& (OverflowX =:. (Nothing, venum overflowProps))
+                      :& (OverflowY =:. (Nothing, venum overflowProps))
+                      :& (Padding =:: Nothing)
+                      :& (Right =:: Nothing)
+                      :& (Top =:: Nothing)
+                      :& (Visibility =:. (Nothing, venum visibilityProps))
+                      :& (Width =:: Nothing)
+                      :& RNil
+    where venum :: [String] -> Maybe String -> IO (Maybe String)
+          venum _ Nothing = return Nothing
+          venum xs (Just f) = do
+            unless (f `elem` xs) (Ex.throw $ Ex.AssertionFailed ("The value should be one of: " ++ intercalate ", " xs))
+            return $ Just f
diff --git a/src/IHaskell/Display/Widgets/Link/DirectionalLink.hs b/src/IHaskell/Display/Widgets/Link/DirectionalLink.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Link/DirectionalLink.hs
@@ -0,0 +1,60 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module IHaskell.Display.Widgets.Link.DirectionalLink
+  ( -- * The DirectionalLink Widget
+    DirectionalLink
+    -- * Constructor
+  , mkDirectionalLink
+    -- * Another constructor
+  , jsdlink
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+
+-- | An 'DirectionalLink' represents a DirectionalLink widget from IPython.html.widgets.
+type DirectionalLink = IPythonWidget 'DirectionalLinkType
+
+-- | Create a new DirectionalLink widget
+mkDirectionalLink :: IO DirectionalLink
+mkDirectionalLink = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+
+  let widgetState = WidgetState $ defaultLinkWidget "DirectionalLinkModel"
+
+  stateIO <- newIORef widgetState
+
+  let widget = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen widget $ toJSON widgetState
+
+  -- Return the DirectionalLink widget
+  return widget
+
+-- | An easier constructor that links two widgets
+jsdlink :: WidgetFieldPair -> WidgetFieldPair -> IO DirectionalLink
+jsdlink wfp1 wfp2 = do
+  dlink <- mkDirectionalLink
+  _ <- setField dlink Source wfp1
+  _ <- setField dlink Target wfp2
+  return dlink
+
+instance IHaskellWidget DirectionalLink where
+  getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/Link/Link.hs b/src/IHaskell/Display/Widgets/Link/Link.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Link/Link.hs
@@ -0,0 +1,60 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module IHaskell.Display.Widgets.Link.Link
+  ( -- * The Link Widget
+    Link
+    -- * Constructor
+  , mkLink
+    -- * Easier constructor
+  , jslink
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+
+-- | An 'Link' represents a Link widget from IPython.html.widgets.
+type Link = IPythonWidget 'LinkType
+
+-- | Create a new link widget
+mkLink :: IO Link
+mkLink = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+
+  let widgetState = WidgetState $ defaultLinkWidget "LinkModel"
+
+  stateIO <- newIORef widgetState
+
+  let widget = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen widget $ toJSON widgetState
+
+  -- Return the link widget
+  return widget
+
+-- | An easier constructor that links two widgets
+jslink :: WidgetFieldPair -> WidgetFieldPair -> IO Link
+jslink wfp1 wfp2 = do
+  link <- mkLink
+  _ <- setField link Source wfp1
+  _ <- setField link Target wfp2
+  return link
+
+instance IHaskellWidget Link where
+  getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/Media/Audio.hs b/src/IHaskell/Display/Widgets/Media/Audio.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Media/Audio.hs
@@ -0,0 +1,60 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module IHaskell.Display.Widgets.Media.Audio
+  ( -- * The Audio Widget
+    AudioWidget
+    -- * Constructor
+  , mkAudio
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+import           Data.Vinyl (Rec(..), (<+>))
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+
+-- | An 'AudioWidget' represents a Audio widget from IPython.html.widgets.
+type AudioWidget = IPythonWidget 'AudioType
+
+-- | Create a new audio widget
+mkAudio :: IO AudioWidget
+mkAudio = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+  layout <- mkLayout
+
+  let mediaAttrs = defaultMediaWidget "AudioView" "AudioModel" layout
+      audioAttrs = (AudioFormat =:: MP3)
+              :& (AutoPlay =:: True)
+              :& (Loop =:: True)
+              :& (Controls =:: True)
+              :& RNil
+      widgetState = WidgetState (mediaAttrs <+> audioAttrs)
+
+  stateIO <- newIORef widgetState
+
+  let widget = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen widget $ toJSON widgetState
+
+  -- Return the audio widget
+  return widget
+
+instance IHaskellWidget AudioWidget where
+  getCommUUID = uuid
+  getBufferPaths _ = [["value"]]
diff --git a/src/IHaskell/Display/Widgets/Media/Image.hs b/src/IHaskell/Display/Widgets/Media/Image.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Media/Image.hs
@@ -0,0 +1,59 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module IHaskell.Display.Widgets.Media.Image
+  ( -- * The Image Widget
+    ImageWidget
+    -- * Constructor
+  , mkImage
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+import           Data.Vinyl (Rec(..), (<+>))
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+
+-- | An 'ImageWidget' represents a Image widget from IPython.html.widgets.
+type ImageWidget = IPythonWidget 'ImageType
+
+-- | Create a new image widget
+mkImage :: IO ImageWidget
+mkImage = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+  layout <- mkLayout
+
+  let mediaAttrs = defaultMediaWidget "ImageView" "ImageModel" layout
+      imageAttrs = (ImageFormat =:: PNG)
+                   :& (Width =:+ 0)
+                   :& (Height =:+ 0)
+                   :& RNil
+      widgetState = WidgetState (mediaAttrs <+> imageAttrs)
+
+  stateIO <- newIORef widgetState
+
+  let widget = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen widget $ toJSON widgetState
+
+  -- Return the image widget
+  return widget
+
+instance IHaskellWidget ImageWidget where
+  getCommUUID = uuid
+  getBufferPaths _ = [["value"]]
diff --git a/src/IHaskell/Display/Widgets/Media/Video.hs b/src/IHaskell/Display/Widgets/Media/Video.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Media/Video.hs
@@ -0,0 +1,62 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module IHaskell.Display.Widgets.Media.Video
+  ( -- * The Video Widget
+    VideoWidget
+    -- * Constructor
+  , mkVideo
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+import           Data.Vinyl (Rec(..), (<+>))
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+
+-- | An 'VideoWidget' represents a video widget from IPython.html.widgets.
+type VideoWidget = IPythonWidget 'VideoType
+
+-- | Create a new video widget
+mkVideo :: IO VideoWidget
+mkVideo = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+  layout <- mkLayout
+
+  let mediaAttrs = defaultMediaWidget "VideoView" "VideoModel" layout
+      videoAttrs = (VideoFormat =:: MP4)
+              :& (Width =:+ 0)
+              :& (Height =:+ 0)
+              :& (AutoPlay =:: True)
+              :& (Loop =:: True)
+              :& (Controls =:: True)
+              :& RNil
+      widgetState = WidgetState (mediaAttrs <+> videoAttrs)
+
+  stateIO <- newIORef widgetState
+
+  let widget = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen widget $ toJSON widgetState
+
+  -- Return the video widget
+  return widget
+
+instance IHaskellWidget VideoWidget where
+  getCommUUID = uuid
+  getBufferPaths _ = [["value"]]
diff --git a/src/IHaskell/Display/Widgets/Output.hs b/src/IHaskell/Display/Widgets/Output.hs
--- a/src/IHaskell/Display/Widgets/Output.hs
+++ b/src/IHaskell/Display/Widgets/Output.hs
@@ -9,9 +9,11 @@
   ( -- * The Output Widget
     OutputWidget
     -- * Constructor
-  , mkOutputWidget
+  , mkOutput
     -- * Using the output widget
-  , appendOutput
+  , appendStdout
+  , appendStderr
+  , appendDisplay
   , clearOutput
   , clearOutput_
   , replaceOutput
@@ -22,23 +24,37 @@
 
 import           Data.Aeson
 import           Data.IORef (newIORef)
+import           Data.Text
+import           Data.Vinyl (Rec(..), (<+>))
 
 import           IHaskell.Display
 import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Types (StreamType(..))
 import           IHaskell.IPython.Message.UUID as U
 
 import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
 
 -- | An 'OutputWidget' represents a Output widget from IPython.html.widgets.
 type OutputWidget = IPythonWidget 'OutputType
 
 -- | Create a new output widget
-mkOutputWidget :: IO OutputWidget
-mkOutputWidget = do
+mkOutput :: IO OutputWidget
+mkOutput = do
   -- Default properties, with a random uuid
   wid <- U.random
+  layout <- mkLayout
 
-  let widgetState = WidgetState $ defaultDOMWidget "OutputView" "OutputModel"
+  let domAttrs = defaultDOMWidget "OutputView" "OutputModel" layout
+      outAttrs = (ViewModule =:! "@jupyter-widgets/output")
+                 :& (ModelModule =:! "@jupyter-widgets/output")
+                 :& (ViewModuleVersion =:! "1.0.0")
+                 :& (ModelModuleVersion =:! "1.0.0")
+                 :& (MsgID =:: "")
+                 :& (Outputs =:: [])
+                 :& RNil
+      widgetState = WidgetState $ domAttrs <+> outAttrs
 
   stateIO <- newIORef widgetState
 
@@ -50,30 +66,49 @@
   -- Return the image widget
   return widget
 
--- | Append to the output widget
-appendOutput :: IHaskellDisplay a => OutputWidget -> a -> IO ()
-appendOutput widget out = do
-  disp <- display out
-  widgetPublishDisplay widget disp
+-- | Appends the Text to the given Stream
+appendStd :: StreamType -> OutputWidget -> Text -> IO ()
+appendStd n out t = do
+  getField out Outputs >>= setField out Outputs . updateOutputs
+  where updateOutputs :: [OutputMsg] -> [OutputMsg]
+        updateOutputs = (++[OutputStream n t])
 
+-- | Appends text to the stdout of an output widget
+appendStdout :: OutputWidget -> Text -> IO ()
+appendStdout = appendStd Stdout
+
+-- | Appends text to the stderr of an output widget
+appendStderr :: OutputWidget -> Text -> IO ()
+appendStderr = appendStd Stderr
+
+-- | Clears the output widget
+clearOutput' :: OutputWidget -> IO ()
+clearOutput' w = do
+  _ <- setField w Outputs []
+  _ <- setField w MsgID ""
+  return ()
+
+-- | Appends anything displayable to an output widget
+appendDisplay :: IHaskellDisplay a => OutputWidget -> a -> IO ()
+appendDisplay o d = do
+  outputs <- getField o Outputs
+  disp <- display d
+  _ <- setField o Outputs $ outputs ++ [OutputData disp]
+  return ()
+
 -- | Clear the output widget immediately
 clearOutput :: OutputWidget -> IO ()
-clearOutput widget = widgetClearOutput widget False
+clearOutput widget = widgetClearOutput False >> clearOutput' widget
 
 -- | Clear the output widget on next append
 clearOutput_ :: OutputWidget -> IO ()
-clearOutput_ widget = widgetClearOutput widget True
+clearOutput_ widget = widgetClearOutput True >> clearOutput' widget
 
 -- | Replace the currently displayed output for output widget
 replaceOutput :: IHaskellDisplay a => OutputWidget -> a -> IO ()
 replaceOutput widget d = do
-  clearOutput_ widget
-  appendOutput widget d
-
-instance IHaskellDisplay OutputWidget where
-  display b = do
-    widgetSendView b
-    return $ Display []
+    disp <- display d
+    setField widget Outputs [OutputData disp]
 
 instance IHaskellWidget OutputWidget where
   getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/Selection/Dropdown.hs b/src/IHaskell/Display/Widgets/Selection/Dropdown.hs
--- a/src/IHaskell/Display/Widgets/Selection/Dropdown.hs
+++ b/src/IHaskell/Display/Widgets/Selection/Dropdown.hs
@@ -18,7 +18,7 @@
 import           Control.Monad (void)
 import           Data.Aeson
 import           Data.IORef (newIORef)
-import           Data.Vinyl (Rec(..), (<+>))
+import qualified Data.Scientific as Sci
 
 import           IHaskell.Display
 import           IHaskell.Eval.Widgets
@@ -26,6 +26,8 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | A 'Dropdown' represents a Dropdown widget from IPython.html.widgets.
 type Dropdown = IPythonWidget 'DropdownType
@@ -35,10 +37,11 @@
 mkDropdown = do
   -- Default properties, with a random uuid
   wid <- U.random
-  let selectionAttrs = defaultSelectionWidget "DropdownView" "DropdownModel"
-      dropdownAttrs = (ButtonStyle =:: DefaultButton) :& RNil
-      widgetState = WidgetState $ selectionAttrs <+> dropdownAttrs
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
+  let widgetState = WidgetState $ defaultSelectionWidget "DropdownView" "DropdownModel" layout $ StyleWidget dstyle
+
   stateIO <- newIORef widgetState
 
   let widget = IPythonWidget wid stateIO
@@ -49,26 +52,11 @@
   -- Return the widget
   return widget
 
-instance IHaskellDisplay Dropdown where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget Dropdown where
   getCommUUID = uuid
   comm widget val _ =
-    case nestedObjectLookup val ["sync_data", "selected_label"] of
-      Just (String label) -> do
-        opts <- getField widget Options
-        case opts of
-          OptionLabels _ -> do
-            void $ setField' widget SelectedLabel label
-            void $ setField' widget SelectedValue label
-          OptionDict ps ->
-            case lookup label ps of
-              Nothing -> return ()
-              Just value -> do
-                void $ setField' widget SelectedLabel label
-                void $ setField' widget SelectedValue value
+    case nestedObjectLookup val ["state", "index"] of
+      Just (Number index) -> do
+        void $ setField' widget OptionalIndex (Just $ Sci.coefficient index)
         triggerSelection widget
       _ -> pure ()
diff --git a/src/IHaskell/Display/Widgets/Selection/RadioButtons.hs b/src/IHaskell/Display/Widgets/Selection/RadioButtons.hs
--- a/src/IHaskell/Display/Widgets/Selection/RadioButtons.hs
+++ b/src/IHaskell/Display/Widgets/Selection/RadioButtons.hs
@@ -18,6 +18,7 @@
 import           Control.Monad (void)
 import           Data.Aeson
 import           Data.IORef (newIORef)
+import qualified Data.Scientific as Sci
 
 import           IHaskell.Display
 import           IHaskell.Eval.Widgets
@@ -25,6 +26,8 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | A 'RadioButtons' represents a RadioButtons widget from IPython.html.widgets.
 type RadioButtons = IPythonWidget 'RadioButtonsType
@@ -34,8 +37,11 @@
 mkRadioButtons = do
   -- Default properties, with a random uuid
   wid <- U.random
-  let widgetState = WidgetState $ defaultSelectionWidget "RadioButtonsView" "RadioButtonsModel"
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
+  let widgetState = WidgetState $ defaultSelectionWidget "RadioButtonsView" "RadioButtonsModel" layout $ StyleWidget dstyle
+
   stateIO <- newIORef widgetState
 
   let widget = IPythonWidget wid stateIO
@@ -46,26 +52,11 @@
   -- Return the widget
   return widget
 
-instance IHaskellDisplay RadioButtons where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget RadioButtons where
   getCommUUID = uuid
   comm widget val _ =
-    case nestedObjectLookup val ["sync_data", "selected_label"] of
-      Just (String label) -> do
-        opts <- getField widget Options
-        case opts of
-          OptionLabels _ -> do
-            void $ setField' widget SelectedLabel label
-            void $ setField' widget SelectedValue label
-          OptionDict ps ->
-            case lookup label ps of
-              Nothing -> pure ()
-              Just value -> do
-                void $ setField' widget SelectedLabel label
-                void $ setField' widget SelectedValue value
+    case nestedObjectLookup val ["state", "index"] of
+      Just (Number index) -> do
+        void $ setField' widget OptionalIndex (Just $ Sci.coefficient index)
         triggerSelection widget
       _ -> pure ()
diff --git a/src/IHaskell/Display/Widgets/Selection/Select.hs b/src/IHaskell/Display/Widgets/Selection/Select.hs
--- a/src/IHaskell/Display/Widgets/Selection/Select.hs
+++ b/src/IHaskell/Display/Widgets/Selection/Select.hs
@@ -18,6 +18,8 @@
 import           Control.Monad (void)
 import           Data.Aeson
 import           Data.IORef (newIORef)
+import qualified Data.Scientific as Sci
+import           Data.Vinyl (Rec(..), (<+>))
 
 import           IHaskell.Display
 import           IHaskell.Eval.Widgets
@@ -25,6 +27,8 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | A 'Select' represents a Select widget from IPython.html.widgets.
 type Select = IPythonWidget 'SelectType
@@ -34,8 +38,14 @@
 mkSelect = do
   -- Default properties, with a random uuid
   wid <- U.random
-  let widgetState = WidgetState $ defaultSelectionWidget "SelectView" "SelectModel"
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
+  let selectionAttrs = defaultSelectionWidget "SelectView" "SelectModel" layout $ StyleWidget dstyle
+      selectAttrs = (Rows =:: Just 5)
+                    :& RNil
+      widgetState = WidgetState $ selectionAttrs <+> selectAttrs
+
   stateIO <- newIORef widgetState
 
   let widget = IPythonWidget wid stateIO
@@ -46,26 +56,11 @@
   -- Return the widget
   return widget
 
-instance IHaskellDisplay Select where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget Select where
   getCommUUID = uuid
   comm widget val _ =
-    case nestedObjectLookup val ["sync_data", "selected_label"] of
-      Just (String label) -> do
-        opts <- getField widget Options
-        case opts of
-          OptionLabels _ -> do
-            void $ setField' widget SelectedLabel label
-            void $ setField' widget SelectedValue label
-          OptionDict ps ->
-            case lookup label ps of
-              Nothing -> pure ()
-              Just value -> do
-                void $ setField' widget SelectedLabel label
-                void $ setField' widget SelectedValue value
+    case nestedObjectLookup val ["state", "index"] of
+      Just (Number index) -> do
+        void $ setField' widget OptionalIndex (Just $ Sci.coefficient index)
         triggerSelection widget
       _ -> pure ()
diff --git a/src/IHaskell/Display/Widgets/Selection/SelectMultiple.hs b/src/IHaskell/Display/Widgets/Selection/SelectMultiple.hs
--- a/src/IHaskell/Display/Widgets/Selection/SelectMultiple.hs
+++ b/src/IHaskell/Display/Widgets/Selection/SelectMultiple.hs
@@ -18,7 +18,9 @@
 import           Control.Monad (void)
 import           Data.Aeson
 import           Data.IORef (newIORef)
+import qualified Data.Scientific as Sci
 import qualified Data.Vector as V
+import           Data.Vinyl (Rec(..), (<+>))
 
 import           IHaskell.Display
 import           IHaskell.Eval.Widgets
@@ -26,6 +28,8 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | A 'SelectMultiple' represents a SelectMultiple widget from IPython.html.widgets.
 type SelectMultiple = IPythonWidget 'SelectMultipleType
@@ -35,8 +39,14 @@
 mkSelectMultiple = do
   -- Default properties, with a random uuid
   wid <- U.random
-  let widgetState = WidgetState $ defaultMultipleSelectionWidget "SelectMultipleView" "SelectMultipleModel"
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
+  let multipleSelectionAttrs = defaultMultipleSelectionWidget "SelectMultipleView" "SelectMultipleModel" layout $ StyleWidget dstyle
+      selectMultipleAttrs = (Rows =:: Just 5)
+                            :& RNil
+      widgetState = WidgetState $ multipleSelectionAttrs <+> selectMultipleAttrs
+
   stateIO <- newIORef widgetState
 
   let widget = IPythonWidget wid stateIO
@@ -47,27 +57,12 @@
   -- Return the widget
   return widget
 
-instance IHaskellDisplay SelectMultiple where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget SelectMultiple where
   getCommUUID = uuid
   comm widget val _ =
-    case nestedObjectLookup val ["sync_data", "selected_labels"] of
-      Just (Array labels) -> do
-        let labelList = map (\(String x) -> x) $ V.toList labels
-        opts <- getField widget Options
-        case opts of
-          OptionLabels _ -> do
-            void $ setField' widget SelectedLabels labelList
-            void $ setField' widget SelectedValues labelList
-          OptionDict ps ->
-            case mapM (`lookup` ps) labelList of
-              Nothing -> pure ()
-              Just valueList -> do
-                void $ setField' widget SelectedLabels labelList
-                void $ setField' widget SelectedValues valueList
+    case nestedObjectLookup val ["state", "index"] of
+      Just (Array indices) -> do
+        let indicesList = map (\(Number x) -> Sci.coefficient x) $ V.toList indices
+        void $ setField' widget Indices indicesList
         triggerSelection widget
       _ -> pure ()
diff --git a/src/IHaskell/Display/Widgets/Selection/SelectionRangeSlider.hs b/src/IHaskell/Display/Widgets/Selection/SelectionRangeSlider.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Selection/SelectionRangeSlider.hs
@@ -0,0 +1,69 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module IHaskell.Display.Widgets.Selection.SelectionRangeSlider
+  ( -- * The SelectionRangeSlider Widget
+    SelectionRangeSlider
+    -- * Constructor
+  , mkSelectionRangeSlider
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Control.Monad (void)
+import           Data.Aeson
+import           Data.IORef (newIORef)
+import qualified Data.Scientific as Sci
+import qualified Data.Vector as V
+import           Data.Vinyl (Rec(..), (<+>), rput)
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
+
+-- | A 'SelectionRangeSlider' represents a SelectionSlider widget from IPyhon.widgets
+type SelectionRangeSlider = IPythonWidget 'SelectionRangeSliderType
+
+-- | Create a new SelectionRangeSlider widget
+mkSelectionRangeSlider :: IO SelectionRangeSlider
+mkSelectionRangeSlider = do
+  wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
+
+  let selectionAttrs = defaultMultipleSelectionWidget "SelectionRangeSliderView" "SelectionRangeSliderModel" layout $ StyleWidget dstyle
+      selectionRangeSliderAttrs = (Orientation =:: HorizontalOrientation)
+                                  :& (ReadOut =:: True)
+                                  :& (ContinuousUpdate =:: True)
+                                  :& RNil
+      widgetState = WidgetState $ rput (Indices =:. ([0,0], rangeSliderVerification)) $ selectionAttrs <+> selectionRangeSliderAttrs
+
+  stateIO <- newIORef widgetState
+
+  let widget = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget and store it in the kernel state
+  widgetSendOpen widget $ toJSON widgetState
+
+  -- Return the created widget
+  return widget
+
+instance IHaskellWidget SelectionRangeSlider where
+  getCommUUID = uuid
+  comm widget val _ =
+    case nestedObjectLookup val ["state", "index"] of
+      Just (Array indices) -> do
+        let indicesList = map (\(Number x) -> Sci.coefficient x) $ V.toList indices
+        void $ setField' widget Indices indicesList
+        triggerSelection widget
+      _ -> pure ()
diff --git a/src/IHaskell/Display/Widgets/Selection/SelectionSlider.hs b/src/IHaskell/Display/Widgets/Selection/SelectionSlider.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Selection/SelectionSlider.hs
@@ -0,0 +1,67 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module IHaskell.Display.Widgets.Selection.SelectionSlider
+  ( -- * The SelectionSlider Widget
+    SelectionSlider
+    -- * Constructor
+  , mkSelectionSlider
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Control.Monad (void)
+import           Data.Aeson
+import           Data.IORef (newIORef)
+import qualified Data.Scientific as Sci
+import           Data.Vinyl (Rec(..), (<+>))
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
+
+-- | A 'SelectionSlider' represents a SelectionSlider widget from IPyhon.widgets
+type SelectionSlider = IPythonWidget 'SelectionSliderType
+
+-- | Create a new SelectionSLider widget
+mkSelectionSlider :: IO SelectionSlider
+mkSelectionSlider = do
+  wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
+
+  let selectionAttrs = defaultSelectionNonemptyWidget "SelectionSliderView" "SelectionSliderModel" layout $ StyleWidget dstyle
+      selectionSliderAttrs = (Orientation =:: HorizontalOrientation)
+                             :& (ReadOut =:: True)
+                             :& (ContinuousUpdate =:: True)
+                             :& RNil
+      widgetState = WidgetState $ selectionAttrs <+> selectionSliderAttrs
+
+  stateIO <- newIORef widgetState
+
+  let widget = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget and store it in the kernel state
+  widgetSendOpen widget $ toJSON widgetState
+
+  -- Return the created widget
+  return widget
+
+instance IHaskellWidget SelectionSlider where
+  getCommUUID = uuid
+  comm widget val _ =
+    case nestedObjectLookup val ["state", "index"] of
+      Just (Number index) -> do
+        void $ setField' widget Index (Sci.coefficient index)
+        triggerSelection widget
+      _ -> pure ()
diff --git a/src/IHaskell/Display/Widgets/Selection/ToggleButtons.hs b/src/IHaskell/Display/Widgets/Selection/ToggleButtons.hs
--- a/src/IHaskell/Display/Widgets/Selection/ToggleButtons.hs
+++ b/src/IHaskell/Display/Widgets/Selection/ToggleButtons.hs
@@ -18,6 +18,7 @@
 import           Control.Monad (void)
 import           Data.Aeson
 import           Data.IORef (newIORef)
+import qualified Data.Scientific as Sci
 import           Data.Vinyl (Rec(..), (<+>))
 
 import           IHaskell.Display
@@ -26,6 +27,8 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | A 'ToggleButtons' represents a ToggleButtons widget from IPython.html.widgets.
 type ToggleButtons = IPythonWidget 'ToggleButtonsType
@@ -35,7 +38,10 @@
 mkToggleButtons = do
   -- Default properties, with a random uuid
   wid <- U.random
-  let selectionAttrs = defaultSelectionWidget "ToggleButtonsView" "ToggleButtonsModel"
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
+
+  let selectionAttrs = defaultSelectionWidget "ToggleButtonsView" "ToggleButtonsModel" layout $ StyleWidget dstyle
       toggleButtonsAttrs = (Tooltips =:: [])
                            :& (Icons =:: [])
                            :& (ButtonStyle =:: DefaultButton)
@@ -52,26 +58,11 @@
   -- Return the widget
   return widget
 
-instance IHaskellDisplay ToggleButtons where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget ToggleButtons where
   getCommUUID = uuid
   comm widget val _ =
-    case nestedObjectLookup val ["sync_data", "selected_label"]  of
-      Just (String label) -> do
-        opts <- getField widget Options
-        case opts of
-          OptionLabels _ -> void $ do
-            void $ setField' widget SelectedLabel label
-            void $ setField' widget SelectedValue label
-          OptionDict ps ->
-            case lookup label ps of
-              Nothing -> pure ()
-              Just value -> do
-                void $ setField' widget SelectedLabel label
-                void $ setField' widget SelectedValue value
+    case nestedObjectLookup val ["state", "index"] of
+      Just (Number index) -> do
+        void $ setField' widget OptionalIndex (Just $ Sci.coefficient index)
         triggerSelection widget
       _ -> pure ()
diff --git a/src/IHaskell/Display/Widgets/Singletons.hs b/src/IHaskell/Display/Widgets/Singletons.hs
--- a/src/IHaskell/Display/Widgets/Singletons.hs
+++ b/src/IHaskell/Display/Widgets/Singletons.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE PolyKinds #-}
@@ -10,14 +11,25 @@
 {-# LANGUAGE InstanceSigs #-}
 {-# LANGUAGE EmptyCase #-}
 {-# LANGUAGE CPP #-}
+{-# LANGUAGE TypeApplications #-}
+#if __GLASGOW_HASKELL__ >= 810
+{-# LANGUAGE StandaloneKindSignatures #-}
+#endif
 
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+
 module IHaskell.Display.Widgets.Singletons where
 
+#if MIN_VERSION_singletons(3,0,0)
+import           Data.Singletons.Base.TH
+import           Data.Eq.Singletons
+#elif MIN_VERSION_singletons(2,4,0)
+import           Data.Singletons.Prelude.Eq
 import           Data.Singletons.TH
-
-#if MIN_VERSION_singletons(2,4,0)
 #else
+import           Data.Singletons.Prelude.Eq
 import           Data.Singletons.Prelude.Ord
+import           Data.Singletons.TH
 #endif
 
 -- Widget properties
@@ -25,29 +37,16 @@
   [d|
 
   data Field = ViewModule
+             | ViewModuleVersion
              | ViewName
              | ModelModule
+             | ModelModuleVersion
              | ModelName
-             | MsgThrottle
-             | Version
              | DisplayHandler
-             | Visible
-             | CSS
              | DOMClasses
+             | Layout
              | Width
              | Height
-             | Padding
-             | Margin
-             | Color
-             | BackgroundColor
-             | BorderColor
-             | BorderWidth
-             | BorderRadius
-             | BorderStyle
-             | FontStyle
-             | FontWeight
-             | FontSize
-             | FontFamily
              | Description
              | ClickHandler
              | SubmitHandler
@@ -57,17 +56,16 @@
              | Tooltip
              | Icon
              | ButtonStyle
-             | B64Value
+             | BSValue
              | ImageFormat
              | BoolValue
-             | Options
-             | SelectedLabel
-             | SelectedValue
+             | OptionsLabels
+             | Index
+             | OptionalIndex
              | SelectionHandler
              | Tooltips
              | Icons
-             | SelectedLabels
-             | SelectedValues
+             | Indices
              | IntValue
              | StepInt
              | MaxInt
@@ -83,22 +81,222 @@
              | LowerFloat
              | UpperFloat
              | Orientation
-             | ShowRange
+             | BaseFloat
              | ReadOut
-             | SliderColor
+             | ReadOutFormat
              | BarStyle
              | ChangeHandler
              | Children
-             | OverflowX
-             | OverflowY
              | BoxStyle
-             | Flex
-             | Pack
-             | Align
              | Titles
              | SelectedIndex
              | ReadOutMsg
-             | Child
-             | Selector
+             | Indent
+             | ContinuousUpdate
+             | Rows
+             | AudioFormat
+             | VideoFormat
+             | AutoPlay
+             | Loop
+             | Controls
+             | Options
+             | EnsureOption
+             | Playing
+             | Repeat
+             | Interval
+             | ShowRepeat
+             | Concise
+             | DateValue
+             | Pressed
+             | Name
+             | Mapping
+             | Connected
+             | Timestamp
+             | Buttons
+             | Axes
+             | ButtonColor
+             | FontWeight
+             | DescriptionWidth
+             | BarColor
+             | HandleColor
+             | ButtonWidth
+             | Target
+             | Source
+             | MsgID
+             | Outputs
+             | Style
+             -- Now the ones for layout
+             -- Every layout property comes with an L before the name to avoid conflict
+             -- The patterns from Layout.Common remove that leading L
+             | LAlignContent
+             | LAlignItems
+             | LAlignSelf
+             | LBorder
+             | LBottom
+             | LDisplay
+             | LFlex
+             | LFlexFlow
+             | LGridArea
+             | LGridAutoColumns
+             | LGridAutoFlow
+             | LGridAutoRows
+             | LGridColumn
+             | LGridGap
+             | LGridRow
+             | LGridTemplateAreas
+             | LGridTemplateColumns
+             | LGridTemplateRows
+             | LHeight
+             | LJustifyContent
+             | LJustifyItems
+             | LLeft
+             | LMargin
+             | LMaxHeight
+             | LMaxWidth
+             | LMinHeight
+             | LMinWidth
+             | LOrder
+             | LOverflow
+             | LOverflowX
+             | LOverflowY
+             | LPadding
+             | LRight
+             | LTop
+             | LVisibility
+             | LWidth
              deriving (Eq, Ord, Show)
+  |]
+
+-- Attributes that aren't synced with the frontend give "" on toKey
+promote
+  [d|
+    -- toKey :: Field -> String
+    toKey ViewModule = "_view_module"
+    toKey ViewModuleVersion = "_view_module_version"
+    toKey ViewName = "_view_name"
+    toKey ModelModule = "_model_module"
+    toKey ModelModuleVersion = "_model_module_version"
+    toKey ModelName = "_model_name"
+    toKey DisplayHandler = "" -- Not sent to the frontend
+    toKey DOMClasses = "_dom_classes"
+    toKey Width = "width"
+    toKey Height = "height"
+    toKey Description = "description"
+    toKey ClickHandler = "" -- Not sent to the frontend
+    toKey SubmitHandler = "" -- Not sent to the frontend
+    toKey Disabled = "disabled"
+    toKey StringValue = "value"
+    toKey Placeholder = "placeholder"
+    toKey Tooltip = "tooltip"
+    toKey Icon = "icon"
+    toKey ButtonStyle = "button_style"
+    toKey BSValue = "value"
+    toKey ImageFormat = "format"
+    toKey AudioFormat = "format"
+    toKey VideoFormat = "format"
+    toKey BoolValue = "value"
+    toKey Index = "index"
+    toKey OptionalIndex = "index"
+    toKey OptionsLabels = "_options_labels"
+    toKey SelectionHandler = "" -- Not sent to the frontend
+    toKey Tooltips = "tooltips"
+    toKey Icons = "icons"
+    toKey Indices = "index"
+    toKey IntValue = "value"
+    toKey StepInt = "step"
+    toKey MinInt = "min"
+    toKey MaxInt = "max"
+    toKey IntPairValue = "value"
+    toKey LowerInt = "min"
+    toKey UpperInt = "max"
+    toKey FloatValue = "value"
+    toKey StepFloat = "step"
+    toKey MinFloat = "min"
+    toKey MaxFloat = "max"
+    toKey FloatPairValue = "value"
+    toKey LowerFloat = "min"
+    toKey UpperFloat = "max"
+    toKey Orientation = "orientation"
+    toKey BaseFloat = "base"
+    toKey ReadOut = "readout"
+    toKey ReadOutFormat = "readout_format"
+    toKey BarStyle = "bar_style"
+    toKey ChangeHandler = "" -- Not sent to the frontend
+    toKey Children = "children"
+    toKey BoxStyle = "box_style"
+    toKey Titles = "_titles"
+    toKey SelectedIndex = "selected_index"
+    toKey ReadOutMsg = "readout"
+    toKey Indent = "indent"
+    toKey ContinuousUpdate = "continuous_update"
+    toKey Rows = "rows"
+    toKey AutoPlay = "autoplay"
+    toKey Loop = "loop"
+    toKey Controls = "controls"
+    toKey Options = "options"
+    toKey EnsureOption = "ensure_option"
+    toKey Playing = "playing"
+    toKey Repeat = "repeat"
+    toKey Interval = "interval"
+    toKey ShowRepeat = "show_repeat"
+    toKey Concise = "concise"
+    toKey DateValue = "value"
+    toKey Pressed = "pressed"
+    toKey Name = "name"
+    toKey Mapping = "mapping"
+    toKey Connected = "connected"
+    toKey Timestamp = "timestamp"
+    toKey Buttons = "buttons"
+    toKey Axes = "axes"
+    toKey Layout = "layout"
+    toKey ButtonColor = "button_color"
+    toKey FontWeight = "font_weight"
+    toKey DescriptionWidth = "description_width"
+    toKey BarColor = "bar_color"
+    toKey HandleColor = "handle_color"
+    toKey ButtonWidth = "button_width"
+    toKey Target = "target"
+    toKey Source = "source"
+    toKey MsgID = "msg_id"
+    toKey Outputs = "outputs"
+    toKey Style = "style"
+    toKey LAlignContent = "align_content"
+    toKey LAlignItems = "align_items"
+    toKey LAlignSelf = "align_self"
+    toKey LBorder = "border"
+    toKey LBottom = "bottom"
+    toKey LDisplay = "display"
+    toKey LFlex = "flex"
+    toKey LFlexFlow = "flex_flow"
+    toKey LGridArea = "grid_area"
+    toKey LGridAutoColumns = "grid_auto_columns"
+    toKey LGridAutoFlow = "grid_auto_flow"
+    toKey LGridAutoRows = "grid_auto_rows"
+    toKey LGridColumn = "grid_column"
+    toKey LGridGap = "grid_gap"
+    toKey LGridRow = "grid_row"
+    toKey LGridTemplateAreas = "grid_template_areas"
+    toKey LGridTemplateColumns = "grid_template_columns"
+    toKey LGridTemplateRows = "grid_template_rows"
+    toKey LHeight = "height"
+    toKey LJustifyContent = "justify_content"
+    toKey LJustifyItems = "justify_items"
+    toKey LLeft = "left"
+    toKey LMargin = "margin"
+    toKey LMaxHeight = "max_height"
+    toKey LMaxWidth = "max_width"
+    toKey LMinHeight = "min_height"
+    toKey LMinWidth = "min_width"
+    toKey LOrder = "order"
+    toKey LOverflow = "overflow"
+    toKey LOverflowX = "overflow_x"
+    toKey LOverflowY = "overflow_y"
+    toKey LPadding = "padding"
+    toKey LRight = "right"
+    toKey LTop = "top"
+    toKey LVisibility = "visibility"
+    toKey LWidth = "width"
+
+    -- hasKey :: Field -> Bool
+    hasKey x = toKey x /= ""
   |]
diff --git a/src/IHaskell/Display/Widgets/String/Combobox.hs b/src/IHaskell/Display/Widgets/String/Combobox.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/String/Combobox.hs
@@ -0,0 +1,68 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module IHaskell.Display.Widgets.String.Combobox
+  ( -- * The Combobox Widget
+    ComboboxWidget
+    -- * Constructor
+  , mkCombobox
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Control.Monad (when)
+import           Data.Aeson
+import           Data.IORef (newIORef)
+import           Data.Vinyl (Rec(..), (<+>))
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
+
+-- | A 'ComboboxWidget' represents a Combobox widget from IPython.html.widgets.
+type ComboboxWidget = IPythonWidget 'ComboboxType
+
+-- | Create a new Combobox widget
+mkCombobox :: IO ComboboxWidget
+mkCombobox = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
+
+  let txtWidget = defaultTextWidget "ComboboxView" "ComboboxModel" layout $ StyleWidget dstyle
+      boxWidget = (Options =:: [])
+                  :& (EnsureOption =:: False)
+                  :& RNil
+      widgetState = WidgetState $ txtWidget <+> boxWidget
+
+  stateIO <- newIORef widgetState
+
+  let widget = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen widget $ toJSON widgetState
+
+  -- Return the widget
+  return widget
+
+instance IHaskellWidget ComboboxWidget where
+  getCommUUID = uuid
+  -- Two possibilities: 1. content -> event -> "submit" 2. sync_data -> value -> <new_value>
+  comm tw val _ = do
+    case nestedObjectLookup val ["state", "value"] of
+      Just (String value) -> setField' tw StringValue value >> triggerChange tw
+      _                 -> pure ()
+    case nestedObjectLookup val ["content", "event"] of
+      Just (String event) -> when (event == "submit") $ triggerSubmit tw
+      _                   -> pure ()
diff --git a/src/IHaskell/Display/Widgets/String/HTML.hs b/src/IHaskell/Display/Widgets/String/HTML.hs
--- a/src/IHaskell/Display/Widgets/String/HTML.hs
+++ b/src/IHaskell/Display/Widgets/String/HTML.hs
@@ -9,7 +9,7 @@
   ( -- * The HTML Widget
     HTMLWidget
     -- * Constructor
-  , mkHTMLWidget
+  , mkHTML
   ) where
 
 -- To keep `cabal repl` happy when running from the ihaskell repo
@@ -23,17 +23,22 @@
 import           IHaskell.IPython.Message.UUID as U
 
 import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | A 'HTMLWidget' represents a HTML widget from IPython.html.widgets.
 type HTMLWidget = IPythonWidget 'HTMLType
 
 -- | Create a new HTML widget
-mkHTMLWidget :: IO HTMLWidget
-mkHTMLWidget = do
+mkHTML :: IO HTMLWidget
+mkHTML = do
   -- Default properties, with a random uuid
   wid <- U.random
-  let widgetState = WidgetState $ defaultStringWidget "HTMLView" "HTMLModel"
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
+  let widgetState = WidgetState $ defaultStringWidget "HTMLView" "HTMLModel" layout $ StyleWidget dstyle
+
   stateIO <- newIORef widgetState
 
   let widget = IPythonWidget wid stateIO
@@ -43,11 +48,6 @@
 
   -- Return the widget
   return widget
-
-instance IHaskellDisplay HTMLWidget where
-  display b = do
-    widgetSendView b
-    return $ Display []
 
 instance IHaskellWidget HTMLWidget where
   getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/String/HTMLMath.hs b/src/IHaskell/Display/Widgets/String/HTMLMath.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/String/HTMLMath.hs
@@ -0,0 +1,53 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module IHaskell.Display.Widgets.String.HTMLMath
+  ( -- * The HTMLMath Widget
+    HTMLMathWidget
+    -- * Constructor
+  , mkHTMLMath
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
+
+-- | A 'HTMLMathWidget' represents a HTML Math widget from IPython.html.widgets.
+type HTMLMathWidget = IPythonWidget 'HTMLMathType
+
+-- | Create a new HTML widget
+mkHTMLMath :: IO HTMLMathWidget
+mkHTMLMath = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
+
+  let widgetState = WidgetState $ defaultStringWidget "HTMLMathView" "HTMLMathModel" layout $ StyleWidget dstyle
+
+  stateIO <- newIORef widgetState
+
+  let widget = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen widget $ toJSON widgetState
+
+  -- Return the widget
+  return widget
+
+instance IHaskellWidget HTMLMathWidget where
+  getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/String/Label.hs b/src/IHaskell/Display/Widgets/String/Label.hs
--- a/src/IHaskell/Display/Widgets/String/Label.hs
+++ b/src/IHaskell/Display/Widgets/String/Label.hs
@@ -9,7 +9,7 @@
   ( -- * The Label Widget
     LabelWidget
     -- * Constructor
-  , mkLabelWidget
+  , mkLabel
   ) where
 
 -- To keep `cabal repl` happy when running from the ihaskell repo
@@ -23,17 +23,22 @@
 import           IHaskell.IPython.Message.UUID as U
 
 import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | A 'LabelWidget' represents a Label widget from IPython.html.widgets.
 type LabelWidget = IPythonWidget 'LabelType
 
 -- | Create a new Label widget
-mkLabelWidget :: IO LabelWidget
-mkLabelWidget = do
+mkLabel :: IO LabelWidget
+mkLabel = do
   -- Default properties, with a random uuid
   wid <- U.random
-  let widgetState = WidgetState $ defaultStringWidget "LabelView" "LabelModel"
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
+  let widgetState = WidgetState $ defaultStringWidget "LabelView" "LabelModel" layout $ StyleWidget dstyle
+
   stateIO <- newIORef widgetState
 
   let widget = IPythonWidget wid stateIO
@@ -43,11 +48,6 @@
 
   -- Return the widget
   return widget
-
-instance IHaskellDisplay LabelWidget where
-  display b = do
-    widgetSendView b
-    return $ Display []
 
 instance IHaskellWidget LabelWidget where
   getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/String/Password.hs b/src/IHaskell/Display/Widgets/String/Password.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/String/Password.hs
@@ -0,0 +1,62 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module IHaskell.Display.Widgets.String.Password
+  ( -- * The Password Widget
+    PasswordWidget
+    -- * Constructor
+  , mkPassword
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Control.Monad (when)
+import           Data.Aeson
+import           Data.IORef (newIORef)
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
+
+-- | A 'PasswordWidget' represents a Password widget from IPython.html.widgets.
+type PasswordWidget = IPythonWidget 'PasswordType
+
+-- | Create a new Password widget
+mkPassword :: IO PasswordWidget
+mkPassword = do
+  -- Default properties, with a random uuid
+  wid <- U.random
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
+
+  let widgetState = WidgetState $ defaultTextWidget "PasswordView" "PasswordModel" layout $ StyleWidget dstyle
+
+  stateIO <- newIORef widgetState
+
+  let widget = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen widget $ toJSON widgetState
+
+  -- Return the widget
+  return widget
+
+instance IHaskellWidget PasswordWidget where
+  getCommUUID = uuid
+  comm tw val _ = do
+    case nestedObjectLookup val ["state", "value"] of
+      Just (String value) -> setField' tw StringValue value >> triggerChange tw
+      _                 -> pure ()
+    case nestedObjectLookup val ["content", "event"] of
+      Just (String event) -> when (event == "submit") $ triggerSubmit tw
+      _                   -> pure ()
diff --git a/src/IHaskell/Display/Widgets/String/Text.hs b/src/IHaskell/Display/Widgets/String/Text.hs
--- a/src/IHaskell/Display/Widgets/String/Text.hs
+++ b/src/IHaskell/Display/Widgets/String/Text.hs
@@ -9,7 +9,7 @@
   ( -- * The Text Widget
     TextWidget
     -- * Constructor
-  , mkTextWidget
+  , mkText
   ) where
 
 -- To keep `cabal repl` happy when running from the ihaskell repo
@@ -18,7 +18,6 @@
 import           Control.Monad (when)
 import           Data.Aeson
 import           Data.IORef (newIORef)
-import           Data.Vinyl (Rec(..), (<+>))
 
 import           IHaskell.Display
 import           IHaskell.Eval.Widgets
@@ -26,19 +25,22 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | A 'TextWidget' represents a Text widget from IPython.html.widgets.
 type TextWidget = IPythonWidget 'TextType
 
 -- | Create a new Text widget
-mkTextWidget :: IO TextWidget
-mkTextWidget = do
+mkText :: IO TextWidget
+mkText = do
   -- Default properties, with a random uuid
   wid <- U.random
-  let strWidget = defaultStringWidget "TextView" "TextModel"
-      txtWidget = (SubmitHandler =:: return ()) :& (ChangeHandler =:: return ()) :& RNil
-      widgetState = WidgetState $ strWidget <+> txtWidget
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
 
+  let widgetState = WidgetState $ defaultTextWidget "TextView" "TextModel" layout $ StyleWidget dstyle
+
   stateIO <- newIORef widgetState
 
   let widget = IPythonWidget wid stateIO
@@ -49,16 +51,11 @@
   -- Return the widget
   return widget
 
-instance IHaskellDisplay TextWidget where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget TextWidget where
   getCommUUID = uuid
-  -- Two possibilities: 1. content -> event -> "submit" 2. sync_data -> value -> <new_value>
+  -- Two possibilities: 1. content -> event -> "submit" 2. state -> value -> <new_value>
   comm tw val _ = do
-    case nestedObjectLookup val ["sync_data", "value"] of
+    case nestedObjectLookup val ["state", "value"] of
       Just (String value) -> setField' tw StringValue value >> triggerChange tw
       _                 -> pure ()
     case nestedObjectLookup val ["content", "event"] of
diff --git a/src/IHaskell/Display/Widgets/String/TextArea.hs b/src/IHaskell/Display/Widgets/String/TextArea.hs
--- a/src/IHaskell/Display/Widgets/String/TextArea.hs
+++ b/src/IHaskell/Display/Widgets/String/TextArea.hs
@@ -25,6 +25,8 @@
 
 import           IHaskell.Display.Widgets.Types
 import           IHaskell.Display.Widgets.Common
+import           IHaskell.Display.Widgets.Layout.LayoutWidget
+import           IHaskell.Display.Widgets.Style.DescriptionStyle
 
 -- | A 'TextArea' represents a Textarea widget from IPython.html.widgets.
 type TextArea = IPythonWidget 'TextAreaType
@@ -34,8 +36,15 @@
 mkTextArea = do
   -- Default properties, with a random uuid
   wid <- U.random
-  let strAttrs = defaultStringWidget "TextareaView" "TextareaModel"
-      wgtAttrs = (ChangeHandler =:: return ()) :& RNil
+  layout <- mkLayout
+  dstyle <- mkDescriptionStyle
+
+  let strAttrs = defaultStringWidget "TextareaView" "TextareaModel" layout $ StyleWidget dstyle
+      wgtAttrs = (Rows =:: Nothing)
+                 :& (Disabled =:: False)
+                 :& (ContinuousUpdate =:: True)
+                 :& (ChangeHandler =:: return ())
+                 :& RNil
       widgetState = WidgetState $ strAttrs <+> wgtAttrs
 
   stateIO <- newIORef widgetState
@@ -48,15 +57,10 @@
   -- Return the widget
   return widget
 
-instance IHaskellDisplay TextArea where
-  display b = do
-    widgetSendView b
-    return $ Display []
-
 instance IHaskellWidget TextArea where
   getCommUUID = uuid
   comm widget val _ =
-    case nestedObjectLookup val ["sync_data", "value"] of
+    case nestedObjectLookup val ["state", "value"] of
       Just (String value) -> do
         void $ setField' widget StringValue value
         triggerChange widget
diff --git a/src/IHaskell/Display/Widgets/Style/ButtonStyle.hs b/src/IHaskell/Display/Widgets/Style/ButtonStyle.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Style/ButtonStyle.hs
@@ -0,0 +1,54 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+
+module IHaskell.Display.Widgets.Style.ButtonStyle
+  ( -- * Button style
+    ButtonStyle
+    -- * Create a new button style
+  , mkButtonStyle
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+import           Data.Vinyl (Rec(..), (<+>))
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+
+-- | A 'ButtonStyle' represents a Button Style from IPython.html.widgets.
+type ButtonStyle = IPythonWidget 'ButtonStyleType
+
+-- | Create a new button style
+mkButtonStyle :: IO ButtonStyle
+mkButtonStyle = do
+  wid <- U.random
+
+  let stl = defaultStyleWidget "ButtonStyleModel"
+      but = (ButtonColor =:: Nothing)
+            :& (FontWeight =:: DefaultWeight)
+            :& RNil
+      btnStlState = WidgetState (stl <+> but)
+
+  stateIO <- newIORef btnStlState
+
+  let style = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen style $ toJSON btnStlState
+
+  -- Return the style widget
+  return style
+
+instance IHaskellWidget ButtonStyle where
+  getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/Style/DescriptionStyle.hs b/src/IHaskell/Display/Widgets/Style/DescriptionStyle.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Style/DescriptionStyle.hs
@@ -0,0 +1,49 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+
+module IHaskell.Display.Widgets.Style.DescriptionStyle
+  ( -- * Description style
+    DescriptionStyle
+    -- * Create a new description style
+  , mkDescriptionStyle
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+
+-- | A 'DescriptionStyle' represents a Button Style from IPython.html.widgets.
+type DescriptionStyle = IPythonWidget 'DescriptionStyleType
+
+-- | Create a new button style
+mkDescriptionStyle :: IO DescriptionStyle
+mkDescriptionStyle = do
+  wid <- U.random
+
+  let stl = defaultDescriptionStyleWidget "DescriptionStyleModel"
+      btnStlState = WidgetState stl
+
+  stateIO <- newIORef btnStlState
+
+  let style = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen style $ toJSON btnStlState
+
+  -- Return the style widget
+  return style
+
+instance IHaskellWidget DescriptionStyle where
+  getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/Style/ProgressStyle.hs b/src/IHaskell/Display/Widgets/Style/ProgressStyle.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Style/ProgressStyle.hs
@@ -0,0 +1,53 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+
+module IHaskell.Display.Widgets.Style.ProgressStyle
+  ( -- * Progress style
+    ProgressStyle
+    -- * Create a new progress style
+  , mkProgressStyle
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+import           Data.Vinyl (Rec(..), (<+>))
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+
+-- | A 'ProgressStyle' represents a Button Style from IPython.html.widgets.
+type ProgressStyle = IPythonWidget 'ProgressStyleType
+
+-- | Create a new button style
+mkProgressStyle :: IO ProgressStyle
+mkProgressStyle = do
+  wid <- U.random
+
+  let stl = defaultDescriptionStyleWidget "ProgressStyleModel"
+      but = (BarColor =:: Nothing)
+            :& RNil
+      btnStlState = WidgetState (stl <+> but)
+
+  stateIO <- newIORef btnStlState
+
+  let style = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen style $ toJSON btnStlState
+
+  -- Return the style widget
+  return style
+
+instance IHaskellWidget ProgressStyle where
+  getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/Style/SliderStyle.hs b/src/IHaskell/Display/Widgets/Style/SliderStyle.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Style/SliderStyle.hs
@@ -0,0 +1,53 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+
+module IHaskell.Display.Widgets.Style.SliderStyle
+  ( -- * Slider style
+    SliderStyle
+    -- * Create a new slider style
+  , mkSliderStyle
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+import           Data.Vinyl (Rec(..), (<+>))
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+
+-- | A 'SliderStyle' represents a Button Style from IPython.html.widgets.
+type SliderStyle = IPythonWidget 'SliderStyleType
+
+-- | Create a new button style
+mkSliderStyle :: IO SliderStyle
+mkSliderStyle = do
+  wid <- U.random
+
+  let stl = defaultDescriptionStyleWidget "SliderStyleModel"
+      but = (HandleColor =:: Nothing)
+            :& RNil
+      btnStlState = WidgetState (stl <+> but)
+
+  stateIO <- newIORef btnStlState
+
+  let style = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen style $ toJSON btnStlState
+
+  -- Return the style widget
+  return style
+
+instance IHaskellWidget SliderStyle where
+  getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/Style/ToggleButtonsStyle.hs b/src/IHaskell/Display/Widgets/Style/ToggleButtonsStyle.hs
new file mode 100644
--- /dev/null
+++ b/src/IHaskell/Display/Widgets/Style/ToggleButtonsStyle.hs
@@ -0,0 +1,54 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+
+module IHaskell.Display.Widgets.Style.ToggleButtonsStyle
+  ( -- * ToggleButtons style
+    ToggleButtonsStyle
+    -- * Create a new toggle buttons style
+  , mkToggleButtonsStyle
+  ) where
+
+-- To keep `cabal repl` happy when running from the ihaskell repo
+import           Prelude
+
+import           Data.Aeson
+import           Data.IORef (newIORef)
+import           Data.Vinyl (Rec(..), (<+>))
+
+import           IHaskell.Display
+import           IHaskell.Eval.Widgets
+import           IHaskell.IPython.Message.UUID as U
+
+import           IHaskell.Display.Widgets.Types
+import           IHaskell.Display.Widgets.Common
+
+-- | A 'ToggleButtonsStyle' represents a Button Style from IPython.html.widgets.
+type ToggleButtonsStyle = IPythonWidget 'ToggleButtonsStyleType
+
+-- | Create a new button style
+mkToggleButtonsStyle :: IO ToggleButtonsStyle
+mkToggleButtonsStyle = do
+  wid <- U.random
+
+  let stl = defaultDescriptionStyleWidget "ToggleButtonsStyleModel"
+      but = (ButtonWidth =:: "")
+            :& (FontWeight =:: DefaultWeight)
+            :& RNil
+      btnStlState = WidgetState (stl <+> but)
+
+  stateIO <- newIORef btnStlState
+
+  let style = IPythonWidget wid stateIO
+
+  -- Open a comm for this widget, and store it in the kernel state
+  widgetSendOpen style $ toJSON btnStlState
+
+  -- Return the style widget
+  return style
+
+instance IHaskellWidget ToggleButtonsStyle where
+  getCommUUID = uuid
diff --git a/src/IHaskell/Display/Widgets/Types.hs b/src/IHaskell/Display/Widgets/Types.hs
--- a/src/IHaskell/Display/Widgets/Types.hs
+++ b/src/IHaskell/Display/Widgets/Types.hs
@@ -15,893 +15,986 @@
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE AutoDeriveTypeable #-}
 {-# LANGUAGE CPP #-}
-
--- | This module houses all the type-trickery needed to make widgets happen.
---
--- All widgets have a corresponding 'WidgetType', and some fields/attributes/properties as defined
--- by the 'WidgetFields' type-family.
---
--- Each widget field corresponds to a concrete haskell type, as given by the 'FieldType'
--- type-family.
---
--- Vinyl records are used to wrap together widget fields into a single 'WidgetState'.
---
--- Singletons are used as a way to represent the promoted types of kind Field. For example:
---
--- @
--- SViewName :: SField ViewName
--- @
---
--- This allows the user to pass the type 'ViewName' without using Data.Proxy. In essence, a
--- singleton is the only inhabitant (other than bottom) of a promoted type. Single element set/type
--- == singleton.
---
--- It also allows the record to wrap values of properties with information about their Field type. A
--- vinyl record is represented as @Rec f ts@, which means that a record is a list of @f x@, where
--- @x@ is a type present in the type-level list @ts@. Thus a 'WidgetState' is essentially a list of
--- field properties wrapped together with the corresponding promoted Field type. See ('=::') for
--- more.
---
--- The properties function can be used to view all the @Field@s associated with a widget object.
---
--- Attributes are represented by the @Attr@ data type, which holds the value of a field, along with
--- the actual @Field@ object and a function to verify validity of changes to the value.
---
--- The IPython widgets expect state updates of the form {"property": value}, where an empty string
--- for numeric values is ignored by the frontend and the default value is used instead. Some numbers
--- need to be sent as numbers (represented by @Integer@), whereas some (css lengths) need to be sent
--- as Strings (@PixCount@).
---
--- Child widgets are expected to be sent as strings of the form "IPY_MODEL_<uuid>", where @<uuid>@
--- represents the uuid of the widget's comm.
---
--- To know more about the IPython messaging specification (as implemented in this package) take a
--- look at the supplied MsgSpec.md.
---
--- Widgets are not able to do console input, the reason for that can be found in the messaging
--- specification.
-module IHaskell.Display.Widgets.Types where
-
-import           Control.Monad (unless, join, when, void)
-import           Control.Applicative ((<$>))
-import qualified Control.Exception as Ex
-import           Data.Typeable (Typeable, TypeRep, typeOf)
-import           Data.IORef (IORef, readIORef, modifyIORef)
-import           Data.Text (Text, pack)
-import           System.IO.Error
-import           System.Posix.IO
-import           Text.Printf (printf)
-
-import           Data.Aeson hiding (pairs)
-import           Data.Aeson.Types (Pair)
-import           Data.Int (Int16)
-#if MIN_VERSION_vinyl(0,9,0)
-import           Data.Vinyl (Rec(..), Dict(..))
-import           Data.Vinyl.Recursive ((<+>), recordToList, reifyConstraint, rmap)
-#else
-import           Data.Vinyl (Rec(..), (<+>), recordToList, reifyConstraint, rmap, Dict(..))
-#endif
-import           Data.Vinyl.Functor (Compose(..), Const(..))
-import           Data.Vinyl.Lens (rget, rput, type (∈))
-import           Data.Vinyl.TypeLevel (RecAll)
-
-#if MIN_VERSION_singletons(2,4,0)
-import           Data.Singletons.Prelude.List
-#else
-import           Data.Singletons.Prelude ((:++))
-#endif
-
-import           Data.Singletons.TH
-
-import           GHC.IO.Exception
-
-import           IHaskell.Eval.Widgets (widgetSendUpdate)
-import           IHaskell.Display (Base64, IHaskellWidget(..))
-import           IHaskell.IPython.Message.UUID
-
-import           IHaskell.Display.Widgets.Singletons (Field, SField)
-import qualified IHaskell.Display.Widgets.Singletons as S
-import           IHaskell.Display.Widgets.Common
-
-#if MIN_VERSION_singletons(2,4,0)
--- Versions of the "singletons" package are tightly tied to the GHC version.
--- Singletons versions 2.3.* and earlier used the type level operator ':++'
--- for appending type level lists while 2.4.* and latter use the normal value
--- level list append operator '++'.
--- To maintain compatibility across GHC versions we keep using the ':++'
--- operator for now.
-type (a :++ b) = a ++ b
-#endif
-
--- Classes from IPython's widget hierarchy. Defined as such to reduce code duplication.
-type WidgetClass = ['S.ViewModule, 'S.ViewName, 'S.ModelModule, 'S.ModelName,
-  'S.MsgThrottle, 'S.Version, 'S.DisplayHandler]
-
-type DOMWidgetClass = WidgetClass :++ ['S.Visible, 'S.CSS, 'S.DOMClasses, 'S.Width, 'S.Height, 'S.Padding,
-  'S.Margin, 'S.Color, 'S.BackgroundColor, 'S.BorderColor, 'S.BorderWidth,
-  'S.BorderRadius, 'S.BorderStyle, 'S.FontStyle, 'S.FontWeight,
-  'S.FontSize, 'S.FontFamily]
-
-type StringClass = DOMWidgetClass :++ ['S.StringValue, 'S.Disabled, 'S.Description, 'S.Placeholder]
-
-type BoolClass = DOMWidgetClass :++ ['S.BoolValue, 'S.Disabled, 'S.Description, 'S.ChangeHandler]
-
-type SelectionClass = DOMWidgetClass :++ ['S.Options, 'S.SelectedValue, 'S.SelectedLabel, 'S.Disabled,
-  'S.Description, 'S.SelectionHandler]
-
-type MultipleSelectionClass = DOMWidgetClass :++ ['S.Options, 'S.SelectedValues, 'S.SelectedLabels, 'S.Disabled,
-  'S.Description, 'S.SelectionHandler]
-
-type IntClass = DOMWidgetClass :++ ['S.IntValue, 'S.Disabled, 'S.Description, 'S.ChangeHandler]
-
-type BoundedIntClass = IntClass :++ ['S.StepInt, 'S.MinInt, 'S.MaxInt]
-
-type IntRangeClass = IntClass :++ ['S.IntPairValue, 'S.LowerInt, 'S.UpperInt]
-
-type BoundedIntRangeClass = IntRangeClass :++ ['S.StepInt, 'S.MinInt, 'S.MaxInt]
-
-type FloatClass = DOMWidgetClass :++ ['S.FloatValue, 'S.Disabled, 'S.Description, 'S.ChangeHandler]
-
-type BoundedFloatClass = FloatClass :++ ['S.StepFloat, 'S.MinFloat, 'S.MaxFloat]
-
-type FloatRangeClass = FloatClass :++ ['S.FloatPairValue, 'S.LowerFloat, 'S.UpperFloat]
-
-type BoundedFloatRangeClass = FloatRangeClass :++ ['S.StepFloat, 'S.MinFloat, 'S.MaxFloat]
-
-type BoxClass = DOMWidgetClass :++ ['S.Children, 'S.OverflowX, 'S.OverflowY, 'S.BoxStyle]
-
-type SelectionContainerClass = BoxClass :++ ['S.Titles, 'S.SelectedIndex, 'S.ChangeHandler]
-
--- Types associated with Fields.
-
-type family FieldType (f :: Field) :: * where
-        FieldType 'S.ViewModule = Text
-        FieldType 'S.ViewName = Text
-        FieldType 'S.ModelModule = Text
-        FieldType 'S.ModelName = Text
-        FieldType 'S.MsgThrottle = Integer
-        FieldType 'S.Version = Integer
-        FieldType 'S.DisplayHandler = IO ()
-        FieldType 'S.Visible = Bool
-        FieldType 'S.CSS = [(Text, Text, Text)]
-        FieldType 'S.DOMClasses = [Text]
-        FieldType 'S.Width = PixCount
-        FieldType 'S.Height = PixCount
-        FieldType 'S.Padding = PixCount
-        FieldType 'S.Margin = PixCount
-        FieldType 'S.Color = Text
-        FieldType 'S.BackgroundColor = Text
-        FieldType 'S.BorderColor = Text
-        FieldType 'S.BorderWidth = PixCount
-        FieldType 'S.BorderRadius = PixCount
-        FieldType 'S.BorderStyle = BorderStyleValue
-        FieldType 'S.FontStyle = FontStyleValue
-        FieldType 'S.FontWeight = FontWeightValue
-        FieldType 'S.FontSize = PixCount
-        FieldType 'S.FontFamily = Text
-        FieldType 'S.Description = Text
-        FieldType 'S.ClickHandler = IO ()
-        FieldType 'S.SubmitHandler = IO ()
-        FieldType 'S.Disabled = Bool
-        FieldType 'S.StringValue = Text
-        FieldType 'S.Placeholder = Text
-        FieldType 'S.Tooltip = Text
-        FieldType 'S.Icon = Text
-        FieldType 'S.ButtonStyle = ButtonStyleValue
-        FieldType 'S.B64Value = Base64
-        FieldType 'S.ImageFormat = ImageFormatValue
-        FieldType 'S.BoolValue = Bool
-        FieldType 'S.Options = SelectionOptions
-        FieldType 'S.SelectedLabel = Text
-        FieldType 'S.SelectedValue = Text
-        FieldType 'S.SelectionHandler = IO ()
-        FieldType 'S.Tooltips = [Text]
-        FieldType 'S.Icons = [Text]
-        FieldType 'S.SelectedLabels = [Text]
-        FieldType 'S.SelectedValues = [Text]
-        FieldType 'S.IntValue = Integer
-        FieldType 'S.StepInt = Integer
-        FieldType 'S.MinInt = Integer
-        FieldType 'S.MaxInt = Integer
-        FieldType 'S.LowerInt = Integer
-        FieldType 'S.UpperInt = Integer
-        FieldType 'S.IntPairValue = (Integer, Integer)
-        FieldType 'S.Orientation = OrientationValue
-        FieldType 'S.ShowRange = Bool
-        FieldType 'S.ReadOut = Bool
-        FieldType 'S.SliderColor = Text
-        FieldType 'S.BarStyle = BarStyleValue
-        FieldType 'S.FloatValue = Double
-        FieldType 'S.StepFloat = Double
-        FieldType 'S.MinFloat = Double
-        FieldType 'S.MaxFloat = Double
-        FieldType 'S.LowerFloat = Double
-        FieldType 'S.UpperFloat = Double
-        FieldType 'S.FloatPairValue = (Double, Double)
-        FieldType 'S.ChangeHandler = IO ()
-        FieldType 'S.Children = [ChildWidget]
-        FieldType 'S.OverflowX = OverflowValue
-        FieldType 'S.OverflowY = OverflowValue
-        FieldType 'S.BoxStyle = BoxStyleValue
-        FieldType 'S.Flex = Int
-        FieldType 'S.Pack = LocationValue
-        FieldType 'S.Align = LocationValue
-        FieldType 'S.Titles = [Text]
-        FieldType 'S.SelectedIndex = Integer
-        FieldType 'S.ReadOutMsg = Text
-        FieldType 'S.Child = Maybe ChildWidget
-        FieldType 'S.Selector = Text
-
--- | Can be used to put different widgets in a list. Useful for dealing with children widgets.
-data ChildWidget = forall w. RecAll Attr (WidgetFields w) ToPairs => ChildWidget (IPythonWidget w)
-
-instance ToJSON ChildWidget where
-  toJSON (ChildWidget x) = toJSON . pack $ "IPY_MODEL_" ++ uuidToString (uuid x)
-
--- Will use a custom class rather than a newtype wrapper with an orphan instance. The main issue is
--- the need of a Bounded instance for Float / Double.
-class CustomBounded a where
-  lowerBound :: a
-  upperBound :: a
-
--- Set according to what IPython widgets use
-instance CustomBounded PixCount where
-  lowerBound = - fromIntegral (maxBound :: Int16)
-  upperBound = fromIntegral (maxBound :: Int16)
-
-instance CustomBounded Integer where
-  lowerBound = - fromIntegral (maxBound :: Int16)
-  upperBound = fromIntegral (maxBound :: Int16)
-
-instance CustomBounded Double where
-  lowerBound = - fromIntegral (maxBound :: Int16)
-  upperBound = fromIntegral (maxBound :: Int16)
-
--- Different types of widgets. Every widget in IPython has a corresponding WidgetType
-data WidgetType = ButtonType
-                | ImageType
-                | OutputType
-                | HTMLType
-                | LabelType
-                | TextType
-                | TextAreaType
-                | CheckBoxType
-                | ToggleButtonType
-                | ValidType
-                | DropdownType
-                | RadioButtonsType
-                | SelectType
-                | ToggleButtonsType
-                | SelectMultipleType
-                | IntTextType
-                | BoundedIntTextType
-                | IntSliderType
-                | IntProgressType
-                | IntRangeSliderType
-                | FloatTextType
-                | BoundedFloatTextType
-                | FloatSliderType
-                | FloatProgressType
-                | FloatRangeSliderType
-                | BoxType
-                | AccordionType
-                | TabType
-
--- Fields associated with a widget
-
-type family WidgetFields (w :: WidgetType) :: [Field] where
-  WidgetFields 'ButtonType =
-                  DOMWidgetClass :++
-                    ['S.Description, 'S.Tooltip, 'S.Disabled, 'S.Icon, 'S.ButtonStyle
-                    ,'S.ClickHandler
-                    ]
-  WidgetFields 'ImageType =
-                  DOMWidgetClass :++ ['S.ImageFormat, 'S.Width, 'S.Height, 'S.B64Value]
-  WidgetFields 'OutputType = DOMWidgetClass
-  WidgetFields 'HTMLType = StringClass
-  WidgetFields 'LabelType = StringClass
-  WidgetFields 'TextType =
-                  StringClass :++ ['S.SubmitHandler, 'S.ChangeHandler]
-
-  -- Type level lists with a single element need both the list and the
-  -- constructor ticked, and a space between the open square bracket and
-  -- the first constructor. See https://ghc.haskell.org/trac/ghc/ticket/15601
-  WidgetFields 'TextAreaType = StringClass :++ '[ 'S.ChangeHandler]
-
-  WidgetFields 'CheckBoxType = BoolClass
-  WidgetFields 'ToggleButtonType =
-                  BoolClass :++ ['S.Tooltip, 'S.Icon, 'S.ButtonStyle]
-  WidgetFields 'ValidType = BoolClass :++ '[ 'S.ReadOutMsg]
-  WidgetFields 'DropdownType = SelectionClass :++ '[ 'S.ButtonStyle]
-  WidgetFields 'RadioButtonsType = SelectionClass
-  WidgetFields 'SelectType = SelectionClass
-  WidgetFields 'ToggleButtonsType =
-                  SelectionClass :++ ['S.Tooltips, 'S.Icons, 'S.ButtonStyle]
-  WidgetFields 'SelectMultipleType = MultipleSelectionClass
-  WidgetFields 'IntTextType = IntClass
-  WidgetFields 'BoundedIntTextType = BoundedIntClass
-  WidgetFields 'IntSliderType =
-                  BoundedIntClass :++
-                    ['S.Orientation, 'S.ShowRange, 'S.ReadOut, 'S.SliderColor]
-  WidgetFields 'IntProgressType =
-                  BoundedIntClass :++ ['S.Orientation, 'S.BarStyle]
-  WidgetFields 'IntRangeSliderType =
-                  BoundedIntRangeClass :++
-                    ['S.Orientation, 'S.ShowRange, 'S.ReadOut, 'S.SliderColor]
-  WidgetFields 'FloatTextType = FloatClass
-  WidgetFields 'BoundedFloatTextType = BoundedFloatClass
-  WidgetFields 'FloatSliderType =
-                  BoundedFloatClass :++
-                    ['S.Orientation, 'S.ShowRange, 'S.ReadOut, 'S.SliderColor]
-  WidgetFields 'FloatProgressType =
-                  BoundedFloatClass :++ ['S.Orientation, 'S.BarStyle]
-  WidgetFields 'FloatRangeSliderType =
-                  BoundedFloatRangeClass :++
-                    ['S.Orientation, 'S.ShowRange, 'S.ReadOut, 'S.SliderColor]
-  WidgetFields 'BoxType = BoxClass
-  WidgetFields 'AccordionType = SelectionContainerClass
-  WidgetFields 'TabType = SelectionContainerClass
-
--- Wrapper around a field's value. A dummy value is sent as an empty string to the frontend.
-data AttrVal a = Dummy a
-               | Real a
-
-unwrap :: AttrVal a -> a
-unwrap (Dummy x) = x
-unwrap (Real x) = x
-
--- Wrapper around a field.
-data Attr (f :: Field) where
-  Attr :: Typeable (FieldType f)
-       => { _value :: AttrVal (FieldType f)
-          , _verify :: FieldType f -> IO (FieldType f)
-          , _field :: Field
-          } -> Attr f
-
-getFieldType :: Attr f -> TypeRep
-getFieldType Attr { _value = attrval } = typeOf $ unwrap attrval
-
-instance ToJSON (FieldType f) => ToJSON (Attr f) where
-  toJSON attr =
-    case _value attr of
-      Dummy _ -> ""
-      Real x  -> toJSON x
-
--- Types that can be converted to Aeson Pairs.
-class ToPairs a where
-  toPairs :: a -> [Pair]
-
--- Attributes that aren't synced with the frontend give [] on toPairs
-instance ToPairs (Attr 'S.ViewModule) where
-  toPairs x = ["_view_module" .= toJSON x]
-
-instance ToPairs (Attr 'S.ViewName) where
-  toPairs x = ["_view_name" .= toJSON x]
-
-instance ToPairs (Attr 'S.ModelModule) where
-  toPairs x = ["_model_module" .= toJSON x]
-
-instance ToPairs (Attr 'S.ModelName) where
-  toPairs x = ["_model_name" .= toJSON x]
-
-instance ToPairs (Attr 'S.MsgThrottle) where
-  toPairs x = ["msg_throttle" .= toJSON x]
-
-instance ToPairs (Attr 'S.Version) where
-  toPairs x = ["version" .= toJSON x]
-
-instance ToPairs (Attr 'S.DisplayHandler) where
-  toPairs _ = [] -- Not sent to the frontend
-
-instance ToPairs (Attr 'S.Visible) where
-  toPairs x = ["visible" .= toJSON x]
-
-instance ToPairs (Attr 'S.CSS) where
-  toPairs x = ["_css" .= toJSON x]
-
-instance ToPairs (Attr 'S.DOMClasses) where
-  toPairs x = ["_dom_classes" .= toJSON x]
-
-instance ToPairs (Attr 'S.Width) where
-  toPairs x = ["width" .= toJSON x]
-
-instance ToPairs (Attr 'S.Height) where
-  toPairs x = ["height" .= toJSON x]
-
-instance ToPairs (Attr 'S.Padding) where
-  toPairs x = ["padding" .= toJSON x]
-
-instance ToPairs (Attr 'S.Margin) where
-  toPairs x = ["margin" .= toJSON x]
-
-instance ToPairs (Attr 'S.Color) where
-  toPairs x = ["color" .= toJSON x]
-
-instance ToPairs (Attr 'S.BackgroundColor) where
-  toPairs x = ["background_color" .= toJSON x]
-
-instance ToPairs (Attr 'S.BorderColor) where
-  toPairs x = ["border_color" .= toJSON x]
-
-instance ToPairs (Attr 'S.BorderWidth) where
-  toPairs x = ["border_width" .= toJSON x]
-
-instance ToPairs (Attr 'S.BorderRadius) where
-  toPairs x = ["border_radius" .= toJSON x]
-
-instance ToPairs (Attr 'S.BorderStyle) where
-  toPairs x = ["border_style" .= toJSON x]
-
-instance ToPairs (Attr 'S.FontStyle) where
-  toPairs x = ["font_style" .= toJSON x]
-
-instance ToPairs (Attr 'S.FontWeight) where
-  toPairs x = ["font_weight" .= toJSON x]
-
-instance ToPairs (Attr 'S.FontSize) where
-  toPairs x = ["font_size" .= toJSON x]
-
-instance ToPairs (Attr 'S.FontFamily) where
-  toPairs x = ["font_family" .= toJSON x]
-
-instance ToPairs (Attr 'S.Description) where
-  toPairs x = ["description" .= toJSON x]
-
-instance ToPairs (Attr 'S.ClickHandler) where
-  toPairs _ = [] -- Not sent to the frontend
-
-instance ToPairs (Attr 'S.SubmitHandler) where
-  toPairs _ = [] -- Not sent to the frontend
-
-instance ToPairs (Attr 'S.Disabled) where
-  toPairs x = ["disabled" .= toJSON x]
-
-instance ToPairs (Attr 'S.StringValue) where
-  toPairs x = ["value" .= toJSON x]
-
-instance ToPairs (Attr 'S.Placeholder) where
-  toPairs x = ["placeholder" .= toJSON x]
-
-instance ToPairs (Attr 'S.Tooltip) where
-  toPairs x = ["tooltip" .= toJSON x]
-
-instance ToPairs (Attr 'S.Icon) where
-  toPairs x = ["icon" .= toJSON x]
-
-instance ToPairs (Attr 'S.ButtonStyle) where
-  toPairs x = ["button_style" .= toJSON x]
-
-instance ToPairs (Attr 'S.B64Value) where
-  toPairs x = ["_b64value" .= toJSON x]
-
-instance ToPairs (Attr 'S.ImageFormat) where
-  toPairs x = ["format" .= toJSON x]
-
-instance ToPairs (Attr 'S.BoolValue) where
-  toPairs x = ["value" .= toJSON x]
-
-instance ToPairs (Attr 'S.SelectedLabel) where
-  toPairs x = ["selected_label" .= toJSON x]
-
-instance ToPairs (Attr 'S.SelectedValue) where
-  toPairs x = ["value" .= toJSON x]
-
-instance ToPairs (Attr 'S.Options) where
-  toPairs x =
-    case _value x of
-      Dummy _                -> labels ("" :: Text)
-      Real (OptionLabels xs) -> labels xs
-      Real (OptionDict xps)  -> labels $ map fst xps
-    where
-      labels xs = ["_options_labels" .= xs]
-
-instance ToPairs (Attr 'S.SelectionHandler) where
-  toPairs _ = [] -- Not sent to the frontend
-
-instance ToPairs (Attr 'S.Tooltips) where
-  toPairs x = ["tooltips" .= toJSON x]
-
-instance ToPairs (Attr 'S.Icons) where
-  toPairs x = ["icons" .= toJSON x]
-
-instance ToPairs (Attr 'S.SelectedLabels) where
-  toPairs x = ["selected_labels" .= toJSON x]
-
-instance ToPairs (Attr 'S.SelectedValues) where
-  toPairs x = ["values" .= toJSON x]
-
-instance ToPairs (Attr 'S.IntValue) where
-  toPairs x = ["value" .= toJSON x]
-
-instance ToPairs (Attr 'S.StepInt) where
-  toPairs x = ["step" .= toJSON x]
-
-instance ToPairs (Attr 'S.MinInt) where
-  toPairs x = ["min" .= toJSON x]
-
-instance ToPairs (Attr 'S.MaxInt) where
-  toPairs x = ["max" .= toJSON x]
-
-instance ToPairs (Attr 'S.IntPairValue) where
-  toPairs x = ["value" .= toJSON x]
-
-instance ToPairs (Attr 'S.LowerInt) where
-  toPairs x = ["min" .= toJSON x]
-
-instance ToPairs (Attr 'S.UpperInt) where
-  toPairs x = ["max" .= toJSON x]
-
-instance ToPairs (Attr 'S.FloatValue) where
-  toPairs x = ["value" .= toJSON x]
-
-instance ToPairs (Attr 'S.StepFloat) where
-  toPairs x = ["step" .= toJSON x]
-
-instance ToPairs (Attr 'S.MinFloat) where
-  toPairs x = ["min" .= toJSON x]
-
-instance ToPairs (Attr 'S.MaxFloat) where
-  toPairs x = ["max" .= toJSON x]
-
-instance ToPairs (Attr 'S.FloatPairValue) where
-  toPairs x = ["value" .= toJSON x]
-
-instance ToPairs (Attr 'S.LowerFloat) where
-  toPairs x = ["min" .= toJSON x]
-
-instance ToPairs (Attr 'S.UpperFloat) where
-  toPairs x = ["max" .= toJSON x]
-
-instance ToPairs (Attr 'S.Orientation) where
-  toPairs x = ["orientation" .= toJSON x]
-
-instance ToPairs (Attr 'S.ShowRange) where
-  toPairs x = ["_range" .= toJSON x]
-
-instance ToPairs (Attr 'S.ReadOut) where
-  toPairs x = ["readout" .= toJSON x]
-
-instance ToPairs (Attr 'S.SliderColor) where
-  toPairs x = ["slider_color" .= toJSON x]
-
-instance ToPairs (Attr 'S.BarStyle) where
-  toPairs x = ["bar_style" .= toJSON x]
-
-instance ToPairs (Attr 'S.ChangeHandler) where
-  toPairs _ = [] -- Not sent to the frontend
-
-instance ToPairs (Attr 'S.Children) where
-  toPairs x = ["children" .= toJSON x]
-
-instance ToPairs (Attr 'S.OverflowX) where
-  toPairs x = ["overflow_x" .= toJSON x]
-
-instance ToPairs (Attr 'S.OverflowY) where
-  toPairs x = ["overflow_y" .= toJSON x]
-
-instance ToPairs (Attr 'S.BoxStyle) where
-  toPairs x = ["box_style" .= toJSON x]
-
-instance ToPairs (Attr 'S.Flex) where
-  toPairs x = ["flex" .= toJSON x]
-
-instance ToPairs (Attr 'S.Pack) where
-  toPairs x = ["pack" .= toJSON x]
-
-instance ToPairs (Attr 'S.Align) where
-  toPairs x = ["align" .= toJSON x]
-
-instance ToPairs (Attr 'S.Titles) where
-  toPairs x = ["_titles" .= toJSON x]
-
-instance ToPairs (Attr 'S.SelectedIndex) where
-  toPairs x = ["selected_index" .= toJSON x]
-
-instance ToPairs (Attr 'S.ReadOutMsg) where
-  toPairs x = ["readout" .= toJSON x]
-
-instance ToPairs (Attr 'S.Child) where
-  toPairs x = ["child" .= toJSON x]
-
-instance ToPairs (Attr 'S.Selector) where
-  toPairs x = ["selector" .= toJSON x]
-
--- | Store the value for a field, as an object parametrized by the Field. No verification is done
--- for these values.
-(=::) :: (SingI f, Typeable (FieldType f)) => Sing f -> FieldType f -> Attr f
-s =:: x = Attr { _value = Real x, _verify = return, _field = reflect s }
-
--- | If the number is in the range, return it. Otherwise raise the appropriate (over/under)flow
--- exception.
-rangeCheck :: (Num a, Ord a) => (a, a) -> a -> IO a
-rangeCheck (l, u) x
-  | l <= x && x <= u = return x
-  | l > x = Ex.throw Ex.Underflow
-  | u < x = Ex.throw Ex.Overflow
-  | otherwise = error "The impossible happened in IHaskell.Display.Widgets.Types.rangeCheck"
-
--- | Store a numeric value, with verification mechanism for its range.
-ranged :: (SingI f, Num (FieldType f), Ord (FieldType f), Typeable (FieldType f))
-       => Sing f -> (FieldType f, FieldType f) -> AttrVal (FieldType f) -> Attr f
-ranged s range x = Attr x (rangeCheck range) (reflect s)
-
--- | Store a numeric value, with the invariant that it stays non-negative. The value set is set as a
--- dummy value if it's equal to zero.
-(=:+) :: (SingI f, Num (FieldType f), CustomBounded (FieldType f), Ord (FieldType f), Typeable (FieldType f))
-      => Sing f -> FieldType f -> Attr f
-s =:+ val = Attr
-              ((if val == 0
-                  then Dummy
-                  else Real)
-                 val)
-              (rangeCheck (0, upperBound))
-              (reflect s)
-
--- | Get a field from a singleton Adapted from: http://stackoverflow.com/a/28033250/2388535
-reflect :: forall (f :: Field). (SingI f) => Sing f -> Field
-reflect = fromSing
-
--- | A record representing an object of the Widget class from IPython
-defaultWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> Rec Attr WidgetClass
-defaultWidget viewName modelName = (ViewModule =:: "jupyter-js-widgets")
-                                   :& (ViewName =:: viewName)
-                                   :& (ModelModule =:: "jupyter-js-widgets")
-                                   :& (ModelName =:: modelName)
-                                   :& (MsgThrottle =:+ 3)
-                                   :& (Version =:: 0)
-                                   :& (DisplayHandler =:: return ())
-                                   :& RNil
-
--- | A record representing an object of the DOMWidget class from IPython
-defaultDOMWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> Rec Attr DOMWidgetClass
-defaultDOMWidget viewName modelName = defaultWidget viewName modelName <+> domAttrs
-  where
-    domAttrs = (Visible =:: True)
-               :& (CSS =:: [])
-               :& (DOMClasses =:: [])
-               :& (Width =:+ 0)
-               :& (Height =:+ 0)
-               :& (Padding =:+ 0)
-               :& (Margin =:+ 0)
-               :& (Color =:: "")
-               :& (BackgroundColor =:: "")
-               :& (BorderColor =:: "")
-               :& (BorderWidth =:+ 0)
-               :& (BorderRadius =:+ 0)
-               :& (BorderStyle =:: DefaultBorder)
-               :& (FontStyle =:: DefaultFont)
-               :& (FontWeight =:: DefaultWeight)
-               :& (FontSize =:+ 0)
-               :& (FontFamily =:: "")
-               :& RNil
-
--- | A record representing a widget of the _String class from IPython
-defaultStringWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> Rec Attr StringClass
-defaultStringWidget viewName modelName = defaultDOMWidget viewName modelName <+> strAttrs
-  where
-    strAttrs = (StringValue =:: "")
-               :& (Disabled =:: False)
-               :& (Description =:: "")
-               :& (Placeholder =:: "")
-               :& RNil
-
--- | A record representing a widget of the _Bool class from IPython
-defaultBoolWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> Rec Attr BoolClass
-defaultBoolWidget viewName modelName = defaultDOMWidget viewName modelName <+> boolAttrs
-  where
-    boolAttrs = (BoolValue =:: False)
-                :& (Disabled =:: False)
-                :& (Description =:: "")
-                :& (ChangeHandler =:: return ())
-                :& RNil
-
--- | A record representing a widget of the _Selection class from IPython
-defaultSelectionWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> Rec Attr SelectionClass
-defaultSelectionWidget viewName modelName = defaultDOMWidget viewName modelName <+> selectionAttrs
-  where
-    selectionAttrs = (Options =:: OptionLabels [])
-                     :& (SelectedValue =:: "")
-                     :& (SelectedLabel =:: "")
-                     :& (Disabled =:: False)
-                     :& (Description =:: "")
-                     :& (SelectionHandler =:: return ())
-                     :& RNil
-
--- | A record representing a widget of the _MultipleSelection class from IPython
-defaultMultipleSelectionWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> Rec Attr MultipleSelectionClass
-defaultMultipleSelectionWidget viewName modelName = defaultDOMWidget viewName modelName <+> mulSelAttrs
-  where
-    mulSelAttrs = (Options =:: OptionLabels [])
-                  :& (SelectedValues =:: [])
-                  :& (SelectedLabels =:: [])
-                  :& (Disabled =:: False)
-                  :& (Description =:: "")
-                  :& (SelectionHandler =:: return ())
-                  :& RNil
-
--- | A record representing a widget of the _Int class from IPython
-defaultIntWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> Rec Attr IntClass
-defaultIntWidget viewName modelName = defaultDOMWidget viewName modelName <+> intAttrs
-  where
-    intAttrs = (IntValue =:: 0)
-               :& (Disabled =:: False)
-               :& (Description =:: "")
-               :& (ChangeHandler =:: return ())
-               :& RNil
-
--- | A record representing a widget of the _BoundedInt class from IPython
-defaultBoundedIntWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> Rec Attr BoundedIntClass
-defaultBoundedIntWidget viewName modelName = defaultIntWidget viewName modelName <+> boundedIntAttrs
-  where
-    boundedIntAttrs = (StepInt =:: 1)
-                      :& (MinInt =:: 0)
-                      :& (MaxInt =:: 100)
-                      :& RNil
-
--- | A record representing a widget of the _BoundedInt class from IPython
-defaultIntRangeWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> Rec Attr IntRangeClass
-defaultIntRangeWidget viewName modelName = defaultIntWidget viewName modelName <+> rangeAttrs
-  where
-    rangeAttrs = (IntPairValue =:: (25, 75))
-                 :& (LowerInt =:: 0)
-                 :& (UpperInt =:: 100)
-                 :& RNil
-
--- | A record representing a widget of the _BoundedIntRange class from IPython
-defaultBoundedIntRangeWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> Rec Attr BoundedIntRangeClass
-defaultBoundedIntRangeWidget viewName modelName = defaultIntRangeWidget viewName modelName <+> boundedIntRangeAttrs
-  where
-    boundedIntRangeAttrs = (StepInt =:+ 1)
-                           :& (MinInt =:: 0)
-                           :& (MaxInt =:: 100)
-                           :& RNil
-
--- | A record representing a widget of the _Float class from IPython
-defaultFloatWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> Rec Attr FloatClass
-defaultFloatWidget viewName modelName = defaultDOMWidget viewName modelName <+> intAttrs
-  where
-    intAttrs = (FloatValue =:: 0)
-               :& (Disabled =:: False)
-               :& (Description =:: "")
-               :& (ChangeHandler =:: return ())
-               :& RNil
-
--- | A record representing a widget of the _BoundedFloat class from IPython
-defaultBoundedFloatWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> Rec Attr BoundedFloatClass
-defaultBoundedFloatWidget viewName modelName = defaultFloatWidget viewName modelName <+> boundedFloatAttrs
-  where
-    boundedFloatAttrs = (StepFloat =:+ 1)
-                        :& (MinFloat =:: 0)
-                        :& (MaxFloat =:: 100)
-                        :& RNil
-
--- | A record representing a widget of the _BoundedFloat class from IPython
-defaultFloatRangeWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> Rec Attr FloatRangeClass
-defaultFloatRangeWidget viewName modelName = defaultFloatWidget viewName modelName <+> rangeAttrs
-  where
-    rangeAttrs = (FloatPairValue =:: (25, 75))
-                 :& (LowerFloat =:: 0)
-                 :& (UpperFloat =:: 100)
-                 :& RNil
-
--- | A record representing a widget of the _BoundedFloatRange class from IPython
-defaultBoundedFloatRangeWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> Rec Attr BoundedFloatRangeClass
-defaultBoundedFloatRangeWidget viewName modelName = defaultFloatRangeWidget viewName modelName <+> boundedFloatRangeAttrs
-  where
-    boundedFloatRangeAttrs = (StepFloat =:+ 1)
-                             :& (MinFloat =:: 0)
-                             :& (MaxFloat =:: 100)
-                             :& RNil
-
--- | A record representing a widget of the _Box class from IPython
-defaultBoxWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> Rec Attr BoxClass
-defaultBoxWidget viewName modelName = defaultDOMWidget viewName modelName <+> intAttrs
-  where
-    intAttrs = (Children =:: [])
-               :& (OverflowX =:: DefaultOverflow)
-               :& (OverflowY =:: DefaultOverflow)
-               :& (BoxStyle =:: DefaultBox)
-               :& RNil
-
--- | A record representing a widget of the _SelectionContainer class from IPython
-defaultSelectionContainerWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> Rec Attr SelectionContainerClass
-defaultSelectionContainerWidget viewName modelName = defaultBoxWidget viewName modelName <+> selAttrs
-  where
-    selAttrs = (Titles =:: [])
-               :& (SelectedIndex =:: 0)
-               :& (ChangeHandler =:: return ())
-               :& RNil
-
-newtype WidgetState w = WidgetState { _getState :: Rec Attr (WidgetFields w) }
-
--- All records with ToPair instances for their Attrs will automatically have a toJSON instance now.
-instance RecAll Attr (WidgetFields w) ToPairs => ToJSON (WidgetState w) where
-  toJSON record =
-    object
-    . concat
-      . recordToList
-        . rmap (\(Compose (Dict x)) -> Const $ toPairs x) $ reifyConstraint (Proxy :: Proxy ToPairs) $ _getState
-                                                                                                         record
-
-data IPythonWidget (w :: WidgetType) =
-       IPythonWidget
-         { uuid :: UUID
-         , state :: IORef (WidgetState w)
-         }
-
--- | Change the value for a field, and notify the frontend about it.
-setField :: (f ∈ WidgetFields w, IHaskellWidget (IPythonWidget w), ToPairs (Attr f))
-         => IPythonWidget w -> SField f -> FieldType f -> IO ()
-setField widget sfield fval = do
-  !newattr <- setField' widget sfield fval
-  let pairs = toPairs newattr
-  unless (null pairs) $ widgetSendUpdate widget (object pairs)
-
--- | Change the value of a field, without notifying the frontend. For internal use.
-setField' :: (f ∈ WidgetFields w, IHaskellWidget (IPythonWidget w))
-          => IPythonWidget w -> SField f -> FieldType f -> IO (Attr f)
-setField' widget sfield val = do
-  attr <- getAttr widget sfield
-  newval <- _verify attr val
-  let newattr = attr { _value = Real newval }
-  modifyIORef (state widget) (WidgetState . rput newattr . _getState)
-  return newattr
-
--- | Pluck an attribute from a record
-getAttr :: (f ∈ WidgetFields w) => IPythonWidget w -> SField f -> IO (Attr f)
-#if MIN_VERSION_vinyl(0,9,0)
-getAttr widget _ = rget <$> _getState <$> readIORef (state widget)
-#else
-getAttr widget sfield = rget sfield <$> _getState <$> readIORef (state widget)
-#endif
-
--- | Get the value of a field.
-getField :: (f ∈ WidgetFields w) => IPythonWidget w -> SField f -> IO (FieldType f)
-getField widget sfield = unwrap . _value <$> getAttr widget sfield
-
--- | Useful with toJSON and OverloadedStrings
-str :: String -> String
-str = id
-
-properties :: IPythonWidget w -> IO ()
-properties widget = do
-  st <- readIORef $ state widget
-  let convert :: Attr f -> Const (Field, TypeRep) f
-      convert attr = Const (_field attr, getFieldType attr)
-
-      renderRow (fname, ftype) = printf "%s ::: %s" (show fname) (show ftype)
-      rows = map renderRow . recordToList . rmap convert $ _getState st
-  mapM_ putStrLn rows
-
--- Helper function for widget to enforce their inability to fetch console input
-noStdin :: IO a -> IO ()
-noStdin action =
-  let handler :: IOException -> IO ()
-      handler e = when (ioeGetErrorType e == InvalidArgument)
-                    (error "Widgets cannot do console input, sorry :)")
-  in Ex.handle handler $ do
-    nullFd <- openFd "/dev/null" WriteOnly Nothing defaultFileFlags
-    oldStdin <- dup stdInput
-    void $ dupTo nullFd stdInput
-    closeFd nullFd
-    void action
-    void $ dupTo oldStdin stdInput
-
--- Trigger events
-triggerEvent :: (FieldType f ~ IO (), f ∈ WidgetFields w) => SField f -> IPythonWidget w -> IO ()
-triggerEvent sfield w = noStdin . join $ getField w sfield
-
-triggerChange :: ('S.ChangeHandler ∈ WidgetFields w) => IPythonWidget w -> IO ()
-triggerChange = triggerEvent ChangeHandler
-
-triggerClick :: ('S.ClickHandler ∈ WidgetFields w) => IPythonWidget w -> IO ()
-triggerClick = triggerEvent ClickHandler
-
-triggerSelection :: ('S.SelectionHandler ∈ WidgetFields w) => IPythonWidget w -> IO ()
-triggerSelection = triggerEvent SelectionHandler
-
-triggerSubmit :: ('S.SubmitHandler ∈ WidgetFields w) => IPythonWidget w -> IO ()
-triggerSubmit = triggerEvent SubmitHandler
-
-triggerDisplay :: ('S.DisplayHandler ∈ WidgetFields w) => IPythonWidget w -> IO ()
-triggerDisplay = triggerEvent DisplayHandler
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+
+-- | This module houses all the type-trickery needed to make widgets happen.
+--
+-- All widgets have a corresponding 'WidgetType', and some fields/attributes/properties as defined
+-- by the 'WidgetFields' type-family.
+--
+-- Each widget field corresponds to a concrete haskell type, as given by the 'FieldType'
+-- type-family.
+--
+-- Vinyl records are used to wrap together widget fields into a single 'WidgetState'.
+--
+-- Singletons are used as a way to represent the promoted types of kind Field. For example:
+--
+-- @
+-- SViewName :: SField ViewName
+-- @
+--
+-- This allows the user to pass the type 'ViewName' without using Data.Proxy. In essence, a
+-- singleton is the only inhabitant (other than bottom) of a promoted type. Single element set/type
+-- == singleton.
+--
+-- It also allows the record to wrap values of properties with information about their Field type. A
+-- vinyl record is represented as @Rec f ts@, which means that a record is a list of @f x@, where
+-- @x@ is a type present in the type-level list @ts@. Thus a 'WidgetState' is essentially a list of
+-- field properties wrapped together with the corresponding promoted Field type. See ('=::') for
+-- more.
+--
+-- The properties function can be used to view all the @Field@s associated with a widget object.
+--
+-- Attributes are represented by the @Attr@ data type, which holds the value of a field, along with
+-- the actual @Field@ object and a function to verify validity of changes to the value.
+--
+-- The IPython widgets expect state updates of the form {"property": value}, where an empty string
+-- for numeric values is ignored by the frontend and the default value is used instead. Some numbers
+-- need to be sent as numbers (represented by @Integer@), whereas some (css lengths) need to be sent
+-- as Strings (@PixCount@).
+--
+-- Child widgets are expected to be sent as strings of the form "IPY_MODEL_<uuid>", where @<uuid>@
+-- represents the uuid of the widget's comm.
+--
+-- To know more about the IPython messaging specification (as implemented in this package) take a
+-- look at the supplied MsgSpec.md.
+--
+-- Widgets are not able to do console input, the reason for that can be found in the messaging
+-- specification.
+module IHaskell.Display.Widgets.Types where
+
+import           Control.Monad (unless, join, when, void,mzero)
+import           Control.Applicative ((<$>))
+import qualified Control.Exception as Ex
+import           Data.Typeable (Typeable, TypeRep, typeOf)
+import           Data.IORef (IORef, readIORef, modifyIORef)
+import           Data.String
+import           Data.Text (Text, pack)
+import           System.IO.Error
+import           System.Posix.IO
+import           Text.Printf (printf)
+
+import           Data.Aeson hiding (pairs)
+import           Data.Aeson.Types (Pair)
+import           Data.ByteString (ByteString)
+import           Data.Int (Int16)
+#if MIN_VERSION_vinyl(0,9,0)
+import           Data.Vinyl (Rec(..), Dict(..))
+import           Data.Vinyl.Recursive ((<+>), recordToList, reifyConstraint, rmap)
+#else
+import           Data.Vinyl (Rec(..), (<+>), recordToList, reifyConstraint, rmap, Dict(..))
+#endif
+import           Data.Vinyl.Functor (Compose(..), Const(..))
+import           Data.Vinyl.Lens (rget, rput, type (∈))
+import           Data.Vinyl.TypeLevel (RecAll)
+
+#if MIN_VERSION_singletons(3,0,0)
+import           Data.List.Singletons
+#elif MIN_VERSION_singletons(2,4,0)
+import           Data.Singletons.Prelude.List
+#else
+import           Data.Singletons.Prelude ((:++))
+#endif
+
+#if MIN_VERSION_singletons(3,0,0)
+import           Data.Singletons.Base.TH
+#else
+import           Data.Singletons.TH
+#endif
+
+import           Data.Text.Lazy (unpack)
+import           Data.Text.Lazy.Encoding
+
+import           GHC.IO.Exception
+
+import           IHaskell.Eval.Widgets (widgetSendUpdate, widgetSendView)
+import           IHaskell.Display (IHaskellWidget(..), IHaskellDisplay(..), Display(..), widgetdisplay, base64)
+import           IHaskell.IPython.Types (StreamType(..))
+import           IHaskell.IPython.Message.UUID
+
+import           IHaskell.Display.Widgets.Singletons (Field, SField, toKey, HasKey)
+import qualified IHaskell.Display.Widgets.Singletons as S
+import           IHaskell.Display.Widgets.Common
+
+#if MIN_VERSION_singletons(2,4,0)
+-- Versions of the "singletons" package are tightly tied to the GHC version.
+-- Singletons versions 2.3.* and earlier used the type level operator ':++'
+-- for appending type level lists while 2.4.* and latter use the normal value
+-- level list append operator '++'.
+-- To maintain compatibility across GHC versions we keep using the ':++'
+-- operator for now.
+type (a :++ b) = a ++ b
+#endif
+
+-- Classes from IPython's widget hierarchy. Defined as such to reduce code duplication.
+type CoreWidgetClass = ['S.ViewModule, 'S.ViewModuleVersion, 'S.ModelModule, 'S.ModelModuleVersion ]
+
+type DOMWidgetClass = ['S.ModelName, 'S.ViewName, 'S.DOMClasses, 'S.Tooltip, 'S.Layout, 'S.DisplayHandler]
+
+type StyleWidgetClass = ['S.ModelName, 'S.ViewName] :++ CoreWidgetClass
+
+type DescriptionWidgetClass = CoreWidgetClass :++ DOMWidgetClass :++ ['S.Description,'S.Style]
+
+type StringClass = DescriptionWidgetClass :++ ['S.StringValue, 'S.Placeholder]
+
+type TextClass = StringClass :++ [ 'S.Disabled, 'S.ContinuousUpdate, 'S.SubmitHandler, 'S.ChangeHandler]
+
+type BoolClass = DescriptionWidgetClass :++ ['S.BoolValue, 'S.Disabled, 'S.ChangeHandler]
+
+type SelectionClass = DescriptionWidgetClass :++ ['S.OptionsLabels, 'S.OptionalIndex, 'S.Disabled, 'S.SelectionHandler]
+
+type SelectionNonemptyClass = DescriptionWidgetClass :++ ['S.OptionsLabels, 'S.Index, 'S.Disabled, 'S.SelectionHandler]
+
+type MultipleSelectionClass = DescriptionWidgetClass :++ ['S.OptionsLabels, 'S.Indices, 'S.Disabled, 'S.SelectionHandler]
+
+type IntClass = DescriptionWidgetClass :++ [ 'S.IntValue, 'S.ChangeHandler ]
+
+type BoundedIntClass = IntClass :++ ['S.MaxInt, 'S.MinInt]
+
+type IntRangeClass = IntClass :++ ['S.IntPairValue, 'S.LowerInt, 'S.UpperInt]
+
+type BoundedIntRangeClass = IntRangeClass :++ ['S.MaxInt, 'S.MinInt]
+
+type FloatClass = DescriptionWidgetClass :++ [ 'S.FloatValue, 'S.ChangeHandler ]
+
+type BoundedFloatClass = FloatClass :++ ['S.MinFloat, 'S.MaxFloat]
+
+type BoundedLogFloatClass = FloatClass :++ [ 'S.MinFloat, 'S.MaxFloat, 'S.BaseFloat ]
+
+type FloatRangeClass = FloatClass :++ '[ 'S.FloatPairValue ]
+
+type BoundedFloatRangeClass = FloatRangeClass :++ ['S.StepFloat, 'S.MinFloat, 'S.MaxFloat]
+
+type BoxClass = CoreWidgetClass :++ DOMWidgetClass :++ ['S.Children, 'S.BoxStyle]
+
+type SelectionContainerClass = BoxClass :++ ['S.Titles, 'S.SelectedIndex, 'S.ChangeHandler]
+
+type MediaClass = CoreWidgetClass :++ DOMWidgetClass :++ '[ 'S.BSValue ]
+
+type DescriptionStyleClass = StyleWidgetClass :++ '[ 'S.DescriptionWidth ]
+
+type LinkClass = CoreWidgetClass :++ ['S.ModelName, 'S.Target, 'S.Source]
+
+-- Types associated with Fields.
+type family FieldType (f :: Field) :: *
+
+type instance FieldType 'S.ViewModule = Text
+type instance FieldType 'S.ViewModuleVersion = Text
+type instance FieldType 'S.ViewName = Text
+type instance FieldType 'S.ModelModule = Text
+type instance FieldType 'S.ModelModuleVersion = Text
+type instance FieldType 'S.ModelName = Text
+type instance FieldType 'S.Layout = IPythonWidget 'LayoutType
+type instance FieldType 'S.DisplayHandler = IO ()
+type instance FieldType 'S.DOMClasses = [Text]
+type instance FieldType 'S.Width = PixCount
+type instance FieldType 'S.Height = PixCount
+type instance FieldType 'S.Description = Text
+type instance FieldType 'S.ClickHandler = IO ()
+type instance FieldType 'S.SubmitHandler = IO ()
+type instance FieldType 'S.Disabled = Bool
+type instance FieldType 'S.StringValue = Text
+type instance FieldType 'S.Placeholder = Text
+type instance FieldType 'S.Tooltip = Maybe Text
+type instance FieldType 'S.Icon = Text
+type instance FieldType 'S.ButtonStyle = ButtonStyleValue
+type instance FieldType 'S.BSValue = JSONByteString
+type instance FieldType 'S.ImageFormat = ImageFormatValue
+type instance FieldType 'S.BoolValue = Bool
+type instance FieldType 'S.OptionsLabels = [Text]
+type instance FieldType 'S.Index = Integer
+type instance FieldType 'S.OptionalIndex = Maybe Integer
+type instance FieldType 'S.SelectionHandler = IO ()
+type instance FieldType 'S.Tooltips = [Text]
+type instance FieldType 'S.Icons = [Text]
+type instance FieldType 'S.Indices = [Integer]
+type instance FieldType 'S.IntValue = Integer
+type instance FieldType 'S.StepInt = Maybe Integer
+type instance FieldType 'S.MinInt = Integer
+type instance FieldType 'S.MaxInt = Integer
+type instance FieldType 'S.LowerInt = Integer
+type instance FieldType 'S.UpperInt = Integer
+type instance FieldType 'S.IntPairValue = (Integer, Integer)
+type instance FieldType 'S.Orientation = OrientationValue
+type instance FieldType 'S.BaseFloat = Double
+type instance FieldType 'S.ReadOut = Bool
+type instance FieldType 'S.ReadOutFormat = Text
+type instance FieldType 'S.BarStyle = BarStyleValue
+type instance FieldType 'S.FloatValue = Double
+type instance FieldType 'S.StepFloat = Maybe Double
+type instance FieldType 'S.MinFloat = Double
+type instance FieldType 'S.MaxFloat = Double
+type instance FieldType 'S.LowerFloat = Double
+type instance FieldType 'S.UpperFloat = Double
+type instance FieldType 'S.FloatPairValue = (Double, Double)
+type instance FieldType 'S.ChangeHandler = IO ()
+type instance FieldType 'S.Children = [ChildWidget]
+type instance FieldType 'S.BoxStyle = BoxStyleValue
+type instance FieldType 'S.Titles = [Text]
+type instance FieldType 'S.SelectedIndex = Maybe Integer
+type instance FieldType 'S.ReadOutMsg = Text
+type instance FieldType 'S.Indent = Bool
+type instance FieldType 'S.ContinuousUpdate = Bool
+type instance FieldType 'S.Rows = Maybe Integer
+type instance FieldType 'S.AudioFormat = AudioFormatValue
+type instance FieldType 'S.VideoFormat = VideoFormatValue
+type instance FieldType 'S.AutoPlay = Bool
+type instance FieldType 'S.Loop = Bool
+type instance FieldType 'S.Controls = Bool
+type instance FieldType 'S.Options = [Text]
+type instance FieldType 'S.EnsureOption = Bool
+type instance FieldType 'S.Playing = Bool
+type instance FieldType 'S.Repeat = Bool
+type instance FieldType 'S.Interval = Integer
+type instance FieldType 'S.ShowRepeat = Bool
+type instance FieldType 'S.Concise = Bool
+type instance FieldType 'S.DateValue = Date
+type instance FieldType 'S.Pressed = Bool
+type instance FieldType 'S.Name = Text
+type instance FieldType 'S.Mapping = Text
+type instance FieldType 'S.Connected = Bool
+type instance FieldType 'S.Timestamp = Double
+type instance FieldType 'S.Buttons = [IPythonWidget 'ControllerButtonType]
+type instance FieldType 'S.Axes = [IPythonWidget 'ControllerAxisType]
+type instance FieldType 'S.ButtonColor = Maybe String
+type instance FieldType 'S.FontWeight = FontWeightValue
+type instance FieldType 'S.DescriptionWidth = String
+type instance FieldType 'S.BarColor = Maybe String
+type instance FieldType 'S.HandleColor = Maybe String
+type instance FieldType 'S.ButtonWidth = String
+type instance FieldType 'S.Target = WidgetFieldPair
+type instance FieldType 'S.Source = WidgetFieldPair
+type instance FieldType 'S.MsgID = Text
+type instance FieldType 'S.Outputs = [OutputMsg]
+type instance FieldType 'S.Style = StyleWidget
+
+-- | Can be used to put different widgets in a list. Useful for dealing with children widgets.
+data ChildWidget = forall w. RecAll Attr (WidgetFields w) ToPairs => ChildWidget (IPythonWidget w)
+
+-- | Can be used to put different styles in a same FieldType.
+data StyleWidget = forall w. RecAll Attr (WidgetFields w) ToPairs => StyleWidget (IPythonWidget w)
+
+instance ToJSON (IPythonWidget w) where
+  toJSON x = toJSON . pack $ "IPY_MODEL_" ++ uuidToString (uuid x)
+
+instance ToJSON ChildWidget where
+  toJSON (ChildWidget x) = toJSON x
+
+instance ToJSON StyleWidget where
+  toJSON (StyleWidget x) = toJSON x
+
+-- Will use a custom class rather than a newtype wrapper with an orphan instance. The main issue is
+-- the need of a Bounded instance for Float / Double.
+class CustomBounded a where
+  lowerBound :: a
+  upperBound :: a
+
+-- Set according to what IPython widgets use
+instance CustomBounded PixCount where
+  lowerBound = - fromIntegral (maxBound :: Int16)
+  upperBound = fromIntegral (maxBound :: Int16)
+
+instance CustomBounded Integer where
+  lowerBound = - fromIntegral (maxBound :: Int16)
+  upperBound = fromIntegral (maxBound :: Int16)
+
+instance CustomBounded Double where
+  lowerBound = - fromIntegral (maxBound :: Int16)
+  upperBound = fromIntegral (maxBound :: Int16)
+
+-- | This type only fits if the field is among the widget's fields, and it has a key
+data WidgetFieldPair = forall w f. (f ∈ WidgetFields w, HasKey f ~ 'True, RecAll Attr (WidgetFields w) ToPairs) => WidgetFieldPair (IPythonWidget w) (SField f) | EmptyWT
+
+instance ToJSON WidgetFieldPair where
+  toJSON EmptyWT = Null
+  toJSON (WidgetFieldPair w f) = toJSON [toJSON w, toJSON $ pack $ toKey $ fromSing f]
+
+-- Different types of widgets. Every widget in IPython has a corresponding WidgetType
+data WidgetType = ButtonType
+                | ColorPickerType
+                | DatePickerType
+                | AudioType
+                | ImageType
+                | VideoType
+                | OutputType
+                | ComboboxType
+                | HTMLType
+                | HTMLMathType
+                | LabelType
+                | PasswordType
+                | TextType
+                | TextAreaType
+                | CheckBoxType
+                | ToggleButtonType
+                | ValidType
+                | DropdownType
+                | RadioButtonsType
+                | SelectType
+                | SelectionSliderType
+                | SelectionRangeSliderType
+                | ToggleButtonsType
+                | SelectMultipleType
+                | IntTextType
+                | BoundedIntTextType
+                | IntSliderType
+                | PlayType
+                | IntProgressType
+                | IntRangeSliderType
+                | FloatTextType
+                | BoundedFloatTextType
+                | FloatSliderType
+                | FloatLogSliderType
+                | FloatProgressType
+                | FloatRangeSliderType
+                | BoxType
+                | GridBoxType
+                | HBoxType
+                | VBoxType
+                | AccordionType
+                | TabType
+                | StackedType
+                | ControllerButtonType
+                | ControllerAxisType
+                | ControllerType
+                | LinkType
+                | DirectionalLinkType
+                | LayoutType
+                | ButtonStyleType
+                | DescriptionStyleType
+                | ProgressStyleType
+                | SliderStyleType
+                | ToggleButtonsStyleType
+
+-- Fields associated with a widget
+
+type family WidgetFields (w :: WidgetType) :: [Field]
+type instance WidgetFields 'ButtonType =
+                DescriptionWidgetClass :++
+                  ['S.Disabled, 'S.Icon, 'S.ButtonStyle,'S.ClickHandler]
+type instance WidgetFields 'ColorPickerType =
+                DescriptionWidgetClass :++
+                  ['S.StringValue, 'S.Concise, 'S.Disabled, 'S.ChangeHandler]
+type instance WidgetFields 'DatePickerType =
+                DescriptionWidgetClass :++
+                  ['S.DateValue, 'S.Disabled, 'S.ChangeHandler]
+
+type instance WidgetFields 'AudioType =
+                MediaClass :++ ['S.AudioFormat, 'S.AutoPlay, 'S.Loop, 'S.Controls]
+type instance WidgetFields 'ImageType =
+                MediaClass :++ ['S.ImageFormat, 'S.Width, 'S.Height]
+type instance WidgetFields 'VideoType =
+                MediaClass :++ ['S.VideoFormat, 'S.Width, 'S.Height, 'S.AutoPlay, 'S.Loop, 'S.Controls]
+
+type instance WidgetFields 'OutputType = DOMWidgetClass :++ ['S.ViewModule,'S.ModelModule,'S.ViewModuleVersion,'S.ModelModuleVersion,'S.MsgID,'S.Outputs]
+type instance WidgetFields 'HTMLType = StringClass
+type instance WidgetFields 'HTMLMathType = StringClass
+type instance WidgetFields 'ComboboxType = TextClass :++ [ 'S.Options, 'S.EnsureOption ]
+type instance WidgetFields 'LabelType = StringClass
+type instance WidgetFields 'PasswordType = TextClass
+type instance WidgetFields 'TextType = TextClass
+
+-- Type level lists with a single element need both the list and the
+-- constructor ticked, and a space between the open square bracket and
+-- the first constructor. See https://ghc.haskell.org/trac/ghc/ticket/15601
+type instance WidgetFields 'TextAreaType =
+                StringClass :++
+                  [ 'S.Rows, 'S.Disabled, 'S.ContinuousUpdate, 'S.ChangeHandler]
+
+type instance WidgetFields 'CheckBoxType = BoolClass :++ '[ 'S.Indent ]
+type instance WidgetFields 'ToggleButtonType = BoolClass :++ ['S.Icon, 'S.ButtonStyle]
+type instance WidgetFields 'ValidType = BoolClass :++ '[ 'S.ReadOutMsg ]
+type instance WidgetFields 'DropdownType = SelectionClass
+type instance WidgetFields 'RadioButtonsType = SelectionClass
+type instance WidgetFields 'SelectType = SelectionClass :++ '[ 'S.Rows ]
+type instance WidgetFields 'SelectionSliderType = SelectionNonemptyClass :++ '[ 'S.Orientation, 'S.ReadOut, 'S.ContinuousUpdate ]
+type instance WidgetFields 'SelectionRangeSliderType = MultipleSelectionClass :++ '[ 'S.Orientation, 'S.ReadOut, 'S.ContinuousUpdate ]
+type instance WidgetFields 'ToggleButtonsType =
+                SelectionClass :++ ['S.Tooltips, 'S.Icons, 'S.ButtonStyle]
+type instance WidgetFields 'SelectMultipleType = MultipleSelectionClass :++ '[ 'S.Rows ]
+type instance WidgetFields 'IntTextType = IntClass :++ [ 'S.Disabled, 'S.ContinuousUpdate, 'S.StepInt ]
+type instance WidgetFields 'BoundedIntTextType = BoundedIntClass :++ [ 'S.Disabled, 'S.ContinuousUpdate, 'S.StepInt ]
+type instance WidgetFields 'IntSliderType =
+                BoundedIntClass :++
+                  [ 'S.StepInt, 'S.Orientation, 'S.ReadOut, 'S.ReadOutFormat, 'S.ContinuousUpdate, 'S.Disabled ]
+type instance WidgetFields 'PlayType =
+                BoundedIntClass :++
+                  [ 'S.Playing, 'S.Repeat, 'S.Interval, 'S.StepInt, 'S.Disabled, 'S.ShowRepeat ]
+type instance WidgetFields 'IntProgressType =
+                BoundedIntClass :++ ['S.Orientation, 'S.BarStyle]
+type instance WidgetFields 'IntRangeSliderType =
+                BoundedIntRangeClass :++
+                  ['S.StepInt, 'S.Orientation, 'S.ReadOut, 'S.ReadOutFormat, 'S.ContinuousUpdate, 'S.Disabled ]
+type instance WidgetFields 'FloatTextType = FloatClass :++ '[ 'S.Disabled, 'S.ContinuousUpdate, 'S.StepFloat ]
+type instance WidgetFields 'BoundedFloatTextType = BoundedFloatClass :++ '[ 'S.Disabled, 'S.ContinuousUpdate, 'S.StepFloat ]
+type instance WidgetFields 'FloatSliderType =
+                BoundedFloatClass :++
+                  ['S.StepFloat, 'S.Orientation, 'S.ReadOut, 'S.ReadOutFormat, 'S.ContinuousUpdate, 'S.Disabled ]
+type instance WidgetFields 'FloatLogSliderType =
+                BoundedLogFloatClass :++
+                  ['S.StepFloat, 'S.Orientation, 'S.ReadOut, 'S.ReadOutFormat, 'S.ContinuousUpdate, 'S.Disabled, 'S.BaseFloat]
+type instance WidgetFields 'FloatProgressType =
+                BoundedFloatClass :++ ['S.Orientation, 'S.BarStyle]
+type instance WidgetFields 'FloatRangeSliderType =
+                BoundedFloatRangeClass :++
+                  ['S.StepFloat, 'S.Orientation, 'S.ReadOut, 'S.ReadOutFormat, 'S.ContinuousUpdate, 'S.Disabled ]
+type instance WidgetFields 'BoxType = BoxClass
+type instance WidgetFields 'GridBoxType = BoxClass
+type instance WidgetFields 'HBoxType = BoxClass
+type instance WidgetFields 'VBoxType = BoxClass
+type instance WidgetFields 'AccordionType = SelectionContainerClass
+type instance WidgetFields 'TabType = SelectionContainerClass
+type instance WidgetFields 'StackedType = SelectionContainerClass
+type instance WidgetFields 'ControllerType =
+  CoreWidgetClass :++ DOMWidgetClass :++
+    ['S.Index, 'S.Name, 'S.Mapping, 'S.Connected, 'S.Timestamp, 'S.Buttons, 'S.Axes, 'S.ChangeHandler ]
+type instance WidgetFields 'ControllerAxisType = CoreWidgetClass :++ DOMWidgetClass :++ '[ 'S.FloatValue, 'S.ChangeHandler ]
+type instance WidgetFields 'ControllerButtonType = CoreWidgetClass :++ DOMWidgetClass :++ [ 'S.FloatValue, 'S.Pressed, 'S.ChangeHandler ]
+type instance WidgetFields 'LinkType = LinkClass
+type instance WidgetFields 'DirectionalLinkType = LinkClass
+
+type instance WidgetFields 'ButtonStyleType = StyleWidgetClass :++ ['S.ButtonColor, 'S.FontWeight]
+type instance WidgetFields 'DescriptionStyleType = DescriptionStyleClass
+type instance WidgetFields 'ProgressStyleType = DescriptionStyleClass :++ '[ 'S.BarColor ]
+type instance WidgetFields 'SliderStyleType = DescriptionStyleClass :++ '[ 'S.HandleColor ]
+type instance WidgetFields 'ToggleButtonsStyleType = DescriptionStyleClass :++ ['S.ButtonWidth,'S.FontWeight]
+
+-- Wrapper around a field's value. A dummy value is sent as an empty string to the frontend.
+data AttrVal a = Dummy a
+               | Real a
+
+unwrap :: AttrVal a -> a
+unwrap (Dummy x) = x
+unwrap (Real x) = x
+
+-- Wrapper around a field.
+data Attr (f :: Field) where
+  Attr :: Typeable (FieldType f)
+       => { _value :: AttrVal (FieldType f)
+          , _verify :: FieldType f -> IO (FieldType f)
+          , _field :: Field
+          , _ro :: Bool
+          } -> Attr f
+
+getFieldType :: Attr f -> TypeRep
+getFieldType Attr { _value = attrval } = typeOf $ unwrap attrval
+
+instance ToJSON (FieldType f) => ToJSON (Attr f) where
+  toJSON attr =
+    case _value attr of
+      Dummy _ -> object []
+      Real x  -> toJSON x
+
+-- Types that can be converted to Aeson Pairs.
+class ToPairs a where
+  toPairs :: a -> [Pair]
+
+-- From https://stackoverflow.com/questions/68648670/duplicate-instance-declaration-using-haskell-singletons
+-- TODO: Check if it can be done with something from Singletons
+instance ToPairs' (HasKey f) f => ToPairs (Attr f) where
+  toPairs = toPairs'
+
+class hk ~ HasKey a => ToPairs' hk a where
+  toPairs' :: Attr a -> [Pair]
+
+instance HasKey f ~ 'False => ToPairs' 'False f where
+  toPairs' _ = []
+
+instance (ToJSON (FieldType f), HasKey f ~ 'True) => ToPairs' 'True f where
+  toPairs' x = [ fromString (toKey $ _field x) .= toJSON x ]
+
+newtype JSONByteString = JSONByteString ByteString
+  deriving (Eq,Ord)
+
+instance ToJSON JSONByteString where
+  toJSON (JSONByteString x) = toJSON $ base64 x
+
+instance IsString JSONByteString where
+  fromString = JSONByteString . fromString
+
+-- | Store the value for a field, as an object parametrized by the Field. No verification is done
+-- for these values.
+(=::) :: (SingI f, Typeable (FieldType f)) => Sing f -> FieldType f -> Attr f
+s =:: x = Attr { _value = Real x, _verify = return, _field = reflect s, _ro = False }
+
+-- | Store the value for a field, with a custom verification
+(=:.) :: (SingI f, Typeable (FieldType f)) => Sing f -> (FieldType f, FieldType f -> IO (FieldType f) ) -> Attr f
+s =:. (x,v) = Attr { _value = Real x, _verify = v, _field = reflect s, _ro = False }
+
+-- | Store the value for a field, making it read only from the frontend
+(=:!) :: (SingI f, Typeable (FieldType f)) => Sing f -> FieldType f -> Attr f
+s =:! x = Attr { _value = Real x, _verify = return, _field = reflect s, _ro = True}
+
+-- | If the number is in the range, return it. Otherwise raise the appropriate (over/under)flow
+-- exception.
+rangeCheck :: (Num a, Ord a) => (a, a) -> a -> IO a
+rangeCheck (l, u) x
+  | l <= x && x <= u = return x
+  | l > x = Ex.throw Ex.Underflow
+  | u < x = Ex.throw Ex.Overflow
+  | otherwise = error "The impossible happened in IHaskell.Display.Widgets.Types.rangeCheck"
+
+rangeSliderVerification :: [Integer] -> IO [Integer]
+rangeSliderVerification xs@[a,b]
+  | a <= b    = return xs
+  | otherwise = Ex.throw $ Ex.AssertionFailed "The first index should be smaller than the second"
+rangeSliderVerification _ = Ex.throw $ Ex.AssertionFailed "There should be two indices"
+
+-- | Store a numeric value, with verification mechanism for its range.
+ranged :: (SingI f, Num (FieldType f), Ord (FieldType f), Typeable (FieldType f))
+       => Sing f -> (FieldType f, FieldType f) -> AttrVal (FieldType f) -> Attr f
+ranged s range x = Attr x (rangeCheck range) (reflect s) False
+
+-- | Store a numeric value, with the invariant that it stays non-negative. The value set is set as a
+-- dummy value if it's equal to zero.
+(=:+) :: (SingI f, Num (FieldType f), CustomBounded (FieldType f), Ord (FieldType f), Typeable (FieldType f))
+      => Sing f -> FieldType f -> Attr f
+s =:+ val = Attr
+              ((if val == 0
+                  then Dummy
+                  else Real)
+                 val)
+              (rangeCheck (0, upperBound))
+              (reflect s)
+              False
+
+-- | Get a field from a singleton Adapted from: http://stackoverflow.com/a/28033250/2388535
+reflect :: forall (f :: Field). (SingI f) => Sing f -> Field
+reflect = fromSing
+
+-- | A record representing a Widget class from IPython from the controls modules
+defaultCoreWidget :: Rec Attr CoreWidgetClass
+defaultCoreWidget = (ViewModule =:! "@jupyter-widgets/controls")
+                    :& (ViewModuleVersion =:! "1.4.0")
+                    :& (ModelModule =:! "@jupyter-widgets/controls")
+                    :& (ModelModuleVersion =:! "1.4.0")
+                    :& RNil
+
+-- | A record representing an object of the DOMWidget class from IPython
+defaultDOMWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> IPythonWidget 'LayoutType -> Rec Attr DOMWidgetClass
+defaultDOMWidget viewName modelName layout = (ModelName =:! modelName)
+                                      :& (ViewName =:! viewName)
+                                      :& (DOMClasses =:: [])
+                                      :& (Tooltip =:: Nothing)
+                                      :& (Layout =:: layout)
+                                      :& (DisplayHandler =:: return ())
+                                      :& RNil
+
+-- | A record representing an object of the DescriptionWidget class from IPython
+defaultDescriptionWidget :: FieldType 'S.ViewName
+                         -> FieldType 'S.ModelName
+                         -> IPythonWidget 'LayoutType
+                         -> StyleWidget
+                         -> Rec Attr DescriptionWidgetClass
+defaultDescriptionWidget v m l d = defaultCoreWidget <+> defaultDOMWidget v m l <+> descriptionAttrs
+  where
+    descriptionAttrs = (Description =:: "")
+                       :& (Style =:: d)
+                       :& RNil
+
+-- | A record representing a widget of the _String class from IPython
+defaultStringWidget :: FieldType 'S.ViewName
+                    -> FieldType 'S.ModelName
+                    -> IPythonWidget 'LayoutType
+                    -> StyleWidget
+                    -> Rec Attr StringClass
+defaultStringWidget viewName modelName l d = defaultDescriptionWidget viewName modelName l d <+> strAttrs
+  where
+    strAttrs = (StringValue =:: "")
+               :& (Placeholder =:: "")
+               :& RNil
+
+-- | A record representing a widget of the Text class from IPython
+defaultTextWidget :: FieldType 'S.ViewName
+                  -> FieldType 'S.ModelName
+                  -> IPythonWidget 'LayoutType
+                  -> StyleWidget
+                  -> Rec Attr TextClass
+defaultTextWidget viewName modelName l d = defaultStringWidget viewName modelName l d <+> txtAttrs
+  where
+    txtAttrs = (Disabled =:: False)
+               :& (ContinuousUpdate =:: True)
+               :& (SubmitHandler =:: return ())
+               :& (ChangeHandler =:: return ())
+               :& RNil
+
+-- | A record representing a widget of the _Bool class from IPython
+defaultBoolWidget :: FieldType 'S.ViewName
+                  -> FieldType 'S.ModelName
+                  -> IPythonWidget 'LayoutType
+                  -> StyleWidget
+                  -> Rec Attr BoolClass
+defaultBoolWidget viewName modelName l d = defaultDescriptionWidget viewName modelName l d <+> boolAttrs
+  where
+    boolAttrs = (BoolValue =:: False)
+                :& (Disabled =:: False)
+                :& (ChangeHandler =:: return ())
+                :& RNil
+
+-- | A record representing a widget of the _Selection class from IPython
+defaultSelectionWidget :: FieldType 'S.ViewName
+                       -> FieldType 'S.ModelName
+                       -> IPythonWidget 'LayoutType
+                       -> StyleWidget
+                       -> Rec Attr SelectionClass
+defaultSelectionWidget viewName modelName l d = defaultDescriptionWidget viewName modelName l d <+> selectionAttrs
+  where
+    selectionAttrs = (OptionsLabels =:: [])
+                     :& (OptionalIndex =:: Nothing)
+                     :& (Disabled =:: False)
+                     :& (SelectionHandler =:: return ())
+                     :& RNil
+
+-- | A record representing a widget of the _SelectionNonempty class from IPython
+defaultSelectionNonemptyWidget :: FieldType 'S.ViewName
+                               -> FieldType 'S.ModelName
+                               -> IPythonWidget 'LayoutType
+                               -> StyleWidget
+                               -> Rec Attr SelectionNonemptyClass
+defaultSelectionNonemptyWidget viewName modelName l d = defaultDescriptionWidget viewName modelName l d <+> selectionAttrs
+  where
+    selectionAttrs = (OptionsLabels =:: [])
+                     :& (Index =:: 0)
+                     :& (Disabled =:: False)
+                     :& (SelectionHandler =:: return ())
+                     :& RNil
+
+-- | A record representing a widget of the _MultipleSelection class from IPython
+defaultMultipleSelectionWidget :: FieldType 'S.ViewName
+                               -> FieldType 'S.ModelName
+                               -> IPythonWidget 'LayoutType
+                               -> StyleWidget
+                               -> Rec Attr MultipleSelectionClass
+defaultMultipleSelectionWidget viewName modelName l d = defaultDescriptionWidget viewName modelName l d <+> mulSelAttrs
+  where
+    mulSelAttrs = (OptionsLabels =:: [])
+                  :& (Indices =:: [])
+                  :& (Disabled =:: False)
+                  :& (SelectionHandler =:: return ())
+                  :& RNil
+
+-- | A record representing a widget of the _Int class from IPython
+defaultIntWidget :: FieldType 'S.ViewName
+                 -> FieldType 'S.ModelName
+                 -> IPythonWidget 'LayoutType
+                 -> StyleWidget
+                 -> Rec Attr IntClass
+defaultIntWidget viewName modelName l d = defaultDescriptionWidget viewName modelName l d <+> intAttrs
+  where
+    intAttrs = (IntValue =:: 0)
+               :& (ChangeHandler =:: return ())
+               :& RNil
+
+-- | A record representing a widget of the _BoundedInt class from IPython
+defaultBoundedIntWidget :: FieldType 'S.ViewName
+                        -> FieldType 'S.ModelName
+                        -> IPythonWidget 'LayoutType
+                        -> StyleWidget
+                        -> Rec Attr BoundedIntClass
+defaultBoundedIntWidget viewName modelName l d = defaultIntWidget viewName modelName l d <+> boundedIntAttrs
+  where
+    boundedIntAttrs = (MaxInt =:: 100)
+                      :& (MinInt =:: 0)
+                      :& RNil
+
+-- | A record representing a widget of the _BoundedInt class from IPython
+defaultIntRangeWidget :: FieldType 'S.ViewName
+                      -> FieldType 'S.ModelName
+                      -> IPythonWidget 'LayoutType
+                      -> StyleWidget
+                      -> Rec Attr IntRangeClass
+defaultIntRangeWidget viewName modelName l d = defaultIntWidget viewName modelName l d <+> rangeAttrs
+  where
+    rangeAttrs = (IntPairValue =:: (25, 75))
+                 :& (LowerInt =:: 0)
+                 :& (UpperInt =:: 100)
+                 :& RNil
+
+-- | A record representing a widget of the _BoundedIntRange class from IPython
+defaultBoundedIntRangeWidget :: FieldType 'S.ViewName
+                             -> FieldType 'S.ModelName
+                             -> IPythonWidget 'LayoutType
+                             -> StyleWidget
+                             -> Rec Attr BoundedIntRangeClass
+defaultBoundedIntRangeWidget viewName modelName l d = defaultIntRangeWidget viewName modelName l d <+> boundedIntRangeAttrs
+  where
+    boundedIntRangeAttrs = (MaxInt =:: 100)
+                           :& (MinInt =:: 0)
+                           :& RNil
+
+-- | A record representing a widget of the _Float class from IPython
+defaultFloatWidget :: FieldType 'S.ViewName
+                   -> FieldType 'S.ModelName
+                   -> IPythonWidget 'LayoutType
+                   -> StyleWidget
+                   -> Rec Attr FloatClass
+defaultFloatWidget viewName modelName l d = defaultDescriptionWidget viewName modelName l d <+> floatAttrs
+  where
+    floatAttrs = (FloatValue =:: 0.0)
+               :& (ChangeHandler =:: return ())
+               :& RNil
+
+-- | A record representing a widget of the _BoundedFloat class from IPython
+defaultBoundedFloatWidget :: FieldType 'S.ViewName
+                          -> FieldType 'S.ModelName
+                          -> IPythonWidget 'LayoutType
+                          -> StyleWidget
+                          -> Rec Attr BoundedFloatClass
+defaultBoundedFloatWidget viewName modelName l d = defaultFloatWidget viewName modelName l d <+> boundedFloatAttrs
+  where
+    boundedFloatAttrs = (MinFloat =:: 0)
+                        :& (MaxFloat =:: 100)
+                        :& RNil
+
+-- | A record representing a widget of the _BoundedLogFloat class from IPython
+defaultBoundedLogFloatWidget :: FieldType 'S.ViewName
+                             -> FieldType 'S.ModelName
+                             -> IPythonWidget 'LayoutType
+                             -> StyleWidget
+                             -> Rec Attr BoundedLogFloatClass
+defaultBoundedLogFloatWidget viewName modelName l d = floatAttrs <+> boundedLogFloatAttrs
+  where
+    floatAttrs = rput (FloatValue =:: 1.0) $ defaultFloatWidget viewName modelName l d
+    boundedLogFloatAttrs = (MinFloat =:: 0.0)
+                           :& (MaxFloat =:: 4.0)
+                           :& (BaseFloat =:: 10.0)
+                           :& RNil
+
+-- | A record representing a widget of the _BoundedFloat class from IPython
+defaultFloatRangeWidget :: FieldType 'S.ViewName
+                        -> FieldType 'S.ModelName
+                        -> IPythonWidget 'LayoutType
+                        -> StyleWidget
+                        -> Rec Attr FloatRangeClass
+defaultFloatRangeWidget viewName modelName l d = defaultFloatWidget viewName modelName l d <+> rangeAttrs
+  where
+    rangeAttrs = (FloatPairValue =:: (0.0, 1.0))
+                 :& RNil
+
+-- | A record representing a widget of the _BoundedFloatRange class from IPython
+defaultBoundedFloatRangeWidget :: FieldType 'S.ViewName
+                               -> FieldType 'S.ModelName
+                               -> IPythonWidget 'LayoutType
+                               -> StyleWidget
+                               -> Rec Attr BoundedFloatRangeClass
+defaultBoundedFloatRangeWidget viewName modelName l d = defaultFloatRangeWidget viewName modelName l d <+> boundedFloatRangeAttrs
+  where
+    boundedFloatRangeAttrs = (StepFloat =:: Just 1)
+                             :& (MinFloat =:: 0)
+                             :& (MaxFloat =:: 100)
+                             :& RNil
+
+-- | A record representing a widget of the _Box class from IPython
+defaultBoxWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> IPythonWidget 'LayoutType -> Rec Attr BoxClass
+defaultBoxWidget viewName modelName layout = defaultCoreWidget <+> defaultDOMWidget viewName modelName layout <+> intAttrs
+  where
+    intAttrs = (Children =:: [])
+               :& (BoxStyle =:: DefaultBox)
+               :& RNil
+
+-- | A record representing a widget of the _SelectionContainer class from IPython
+defaultSelectionContainerWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> IPythonWidget 'LayoutType -> Rec Attr SelectionContainerClass
+defaultSelectionContainerWidget viewName modelName layout = defaultBoxWidget viewName modelName layout <+> selAttrs
+  where
+    selAttrs = (Titles =:: [])
+               :& (SelectedIndex =:: Nothing)
+               :& (ChangeHandler =:: return ())
+               :& RNil
+
+-- | A record representing a widget of the _Media class from IPython
+defaultMediaWidget :: FieldType 'S.ViewName -> FieldType 'S.ModelName -> IPythonWidget 'LayoutType -> Rec Attr MediaClass
+defaultMediaWidget viewName modelName layout = defaultCoreWidget <+> defaultDOMWidget viewName modelName layout <+> mediaAttrs
+  where
+    mediaAttrs = (BSValue =:: "")
+                 :& RNil
+
+defaultLinkWidget :: FieldType 'S.ModelName -> Rec Attr LinkClass
+defaultLinkWidget modelName = defaultCoreWidget <+> linkAttrs
+  where
+    linkAttrs = (ModelName =:! modelName)
+                :& (Target =:: EmptyWT)
+                :& (Source =:: EmptyWT)
+                :& RNil
+
+-- | A record representing a widget of the Style class from IPython
+defaultStyleWidget :: FieldType 'S.ModelName -> Rec Attr StyleWidgetClass
+defaultStyleWidget modelName = (ModelName =:! modelName)
+                              :& (ViewName =:! "StyleView")
+                              :& (ViewModule =:! "@jupyter-widgets/base")
+                              :& (ViewModuleVersion =:! "1.1.0")
+                              :& (ModelModule =:! "@jupyter-widgets/controls")
+                              :& (ModelModuleVersion =:! "1.4.0")
+                              :& RNil
+
+-- | A record representing a widget of the DescriptionStyle class from IPython
+defaultDescriptionStyleWidget :: FieldType 'S.ModelName -> Rec Attr DescriptionStyleClass
+defaultDescriptionStyleWidget modelName = defaultStyleWidget modelName <+> dstyle
+  where
+    dstyle = (DescriptionWidth =:: "")
+            :& RNil
+
+newtype WidgetState w = WidgetState { _getState :: Rec Attr (WidgetFields w) }
+
+-- All records with ToPair instances for their Attrs will automatically have a toJSON instance now.
+instance RecAll Attr (WidgetFields w) ToPairs => ToJSON (WidgetState w) where
+  toJSON record =
+    object
+    . concat
+      . recordToList
+        . rmap (\(Compose (Dict x)) -> Const $ toPairs x) $ reifyConstraint (Proxy :: Proxy ToPairs) $ _getState
+                                                                                                         record
+
+data IPythonWidget (w :: WidgetType) =
+       IPythonWidget
+         { uuid :: UUID
+         , state :: IORef (WidgetState w)
+         }
+
+-- | Change the value for a field, and notify the frontend about it. Doesn't work if the field is read only.
+setField :: (f ∈ WidgetFields w, IHaskellWidget (IPythonWidget w), ToPairs (Attr f))
+         => IPythonWidget w -> SField f -> FieldType f -> IO ()
+setField widget sfield fval = do
+  attr <- getAttr widget sfield
+  when (_ro attr) $ error ("The field " ++ show (fromSing sfield) ++ " is read only")
+  !newattr <- setField' widget sfield fval
+  let pairs = toPairs newattr
+  unless (null pairs) $ widgetSendUpdate widget (object pairs)
+
+-- | Change the value of a field, without notifying the frontend and without checking if is read only. For internal use.
+setField' :: (f ∈ WidgetFields w, IHaskellWidget (IPythonWidget w))
+          => IPythonWidget w -> SField f -> FieldType f -> IO (Attr f)
+setField' widget sfield val = do
+  attr <- getAttr widget sfield
+  newval <- _verify attr val
+  let newattr = attr { _value = Real newval }
+  modifyIORef (state widget) (WidgetState . rput newattr . _getState)
+  return newattr
+
+-- | Pluck an attribute from a record
+getAttr :: (f ∈ WidgetFields w) => IPythonWidget w -> SField f -> IO (Attr f)
+#if MIN_VERSION_vinyl(0,9,0)
+getAttr widget _ = rget <$> _getState <$> readIORef (state widget)
+#else
+getAttr widget sfield = rget sfield <$> _getState <$> readIORef (state widget)
+#endif
+
+-- | Get the value of a field.
+getField :: (f ∈ WidgetFields w) => IPythonWidget w -> SField f -> IO (FieldType f)
+getField widget sfield = unwrap . _value <$> getAttr widget sfield
+
+-- | Useful with toJSON and OverloadedStrings
+str :: String -> String
+str = id
+
+-- | Displays on stdout the properties (and its types) of a given widget
+properties :: IPythonWidget w -> IO ()
+properties widget = do
+  st <- readIORef $ state widget
+  let convert :: Attr f -> Const (Field, TypeRep) f
+      convert attr = Const (_field attr, getFieldType attr)
+
+      renderRow (fname, ftype) = printf "%s ::: %s" (show fname) (show ftype)
+      rows = map renderRow . recordToList . rmap convert $ _getState st
+  mapM_ putStrLn rows
+
+-- Helper function for widget to enforce their inability to fetch console input
+noStdin :: IO a -> IO ()
+noStdin action =
+  let handler :: IOException -> IO ()
+      handler e = when (ioeGetErrorType e == InvalidArgument)
+                    (error "Widgets cannot do console input, sorry :)")
+  in Ex.handle handler $ do
+    nullFd <- openFd "/dev/null" WriteOnly Nothing defaultFileFlags
+    oldStdin <- dup stdInput
+    void $ dupTo nullFd stdInput
+    closeFd nullFd
+    void action
+    void $ dupTo oldStdin stdInput
+
+-- | Common function for the different trigger events
+triggerEvent :: (FieldType f ~ IO (), f ∈ WidgetFields w) => SField f -> IPythonWidget w -> IO ()
+triggerEvent sfield w = noStdin . join $ getField w sfield
+
+-- | Called when the value of an attribute is changed on the front-end
+triggerChange :: ('S.ChangeHandler ∈ WidgetFields w) => IPythonWidget w -> IO ()
+triggerChange = triggerEvent ChangeHandler
+
+-- | Called when the button is clicked
+triggerClick :: ('S.ClickHandler ∈ WidgetFields w) => IPythonWidget w -> IO ()
+triggerClick = triggerEvent ClickHandler
+
+-- | Called when a selection is made in a selection widget
+triggerSelection :: ('S.SelectionHandler ∈ WidgetFields w) => IPythonWidget w -> IO ()
+triggerSelection = triggerEvent SelectionHandler
+
+-- | Called when the text is submited in a text widget (or combobox/password)
+triggerSubmit :: ('S.SubmitHandler ∈ WidgetFields w) => IPythonWidget w -> IO ()
+triggerSubmit = triggerEvent SubmitHandler
+
+-- | Called when the widget is displayed on the notebook
+triggerDisplay :: ('S.DisplayHandler ∈ WidgetFields w) => IPythonWidget w -> IO ()
+triggerDisplay = triggerEvent DisplayHandler
+
+-- | Every IHaskellWidget widget has the same IHaskellDisplay instance, for this
+-- reason we need to use FlexibleContexts. The display implementation can still
+-- be overriden per widget
+instance IHaskellWidget (IPythonWidget w) => IHaskellDisplay (IPythonWidget w) where
+  display b = do
+    widgetSendView b -- Keeping compatibility with classic notebook
+    return $ Display [ widgetdisplay $ unpack $ decodeUtf8 $ encode $ object [
+      "model_id" .= getCommUUID b,
+      "version_major" .= version_major,
+      "version_minor" .= version_minor] ]
+    where
+      version_major = 2 :: Int
+      version_minor = 0 :: Int
+
+-- | The date class from IPython
+data Date
+  -- | No date specified. used by default
+  = NullDate
+  -- | Date year month day
+  | Date Integer Integer Integer deriving (Eq,Ord)
+
+defaultDate :: Date
+defaultDate = NullDate
+
+instance Show Date where
+  show NullDate = "NullDate"
+  show (Date y m d) = printf "%04d-%02d-%02d" y m d
+
+instance ToJSON Date where
+  toJSON NullDate = object []
+  toJSON (Date y m d) = object [ "year" .= toJSON y
+                               , "month" .= toJSON (m-1) -- In the frontend months go from 0 to 11
+                               , "date" .= toJSON d
+                               ]
+
+instance FromJSON Date where
+  parseJSON (Object v) = Date
+    <$> v .: "year"
+    <*> ((+1) <$> v .: "month")
+    <*> v .: "date"
+  parseJSON Null = pure NullDate
+  parseJSON _ = mzero
+
+-- | Allows you to unlink a jslink
+unlink :: ('S.Source ∈ WidgetFields w, 'S.Target ∈ WidgetFields w, IHaskellWidget (IPythonWidget w))
+       => IPythonWidget w
+       -> IO (IPythonWidget w)
+unlink w = do
+  _ <- setField' w Source EmptyWT
+  _ <- setField' w Target EmptyWT
+  return w
+
+data OutputMsg = OutputStream StreamType Text | OutputData Display deriving (Show)
+
+instance ToJSON OutputMsg where
+  toJSON (OutputStream n t) = object [ "output_type" .= str "stream"
+                                     , "name" .= toJSON n
+                                     , "text" .= toJSON t
+                                     ]
+  toJSON (OutputData d)     = object [ "output_type" .= str "display_data"
+                                     , "data" .= toJSON d
+                                     , "metadata" .= object []
+                                     ]
