diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,97 @@
+# ChangeLog for yesod-form
+
+## 1.7.9.3
+
+* Support `yesod-core` 1.7
+
+## 1.7.9.2
+
+* Improve deprecation messages for `radioField` and `checkboxesField` [#1902](https://github.com/yesodweb/yesod/pull/1902)
+
+## 1.7.9.1
+
+* Set `base >= 4.11` for less CPP and imports [#1876](https://github.com/yesodweb/yesod/pull/1876)
+
+## 1.7.9
+
+* Added `checkboxesField'` for creating checkbox in more correct way than original `checkboxesField`
+  Function `checkboxesField` marked as deprecated. [#1843](https://github.com/yesodweb/yesod/pull/1843)
+
+## 1.7.8
+
+* Added `radioField'` for creating radio button in more correct way than original `radioField`.
+  Function `radioField` marked as deprecated. [#1842](https://github.com/yesodweb/yesod/pull/1842)
+
+## 1.7.7
+
+* Added `optionsFromList'` to create an OptionList from a List, using the PathPiece instance for the external value and
+a custom function for the user-facing value. Also added `optionsEnum'` to create an OptionList from an enumeration
+[#1828](https://github.com/yesodweb/yesod/pull/1828)
+
+## 1.7.6
+
+* Added `datetimeLocalField` for creating a html `<input type="datetime-local">` [#1817](https://github.com/yesodweb/yesod/pull/1817)
+
+## 1.7.5
+
+* Add Romanian translation [#1801](https://github.com/yesodweb/yesod/pull/1801)
+
+## 1.7.4
+
+* Added a `Monad AForm` instance only when `transformers` >= 0.6 [#1795](https://github.com/yesodweb/yesod/pull/1795)
+
+## 1.7.3
+
+* Fixed `radioField` according to Bootstrap 3 docs. [#1783](https://github.com/yesodweb/yesod/pull/1783)
+
+## 1.7.2
+
+* Added `withRadioField` and re-express `radioField` into that. [#1775](https://github.com/yesodweb/yesod/pull/1775)
+
+## 1.7.1
+
+* Added `colorField` for creating a html color field (`<input type="color">`) [#1748](https://github.com/yesodweb/yesod/pull/1748)
+
+## 1.7.0
+
+* Extended `OptionList` by `OptionListGrouped` and implemented grouped select fields (`<select>` with `<optgroup>`) [#1722](https://github.com/yesodweb/yesod/pull/1722)
+
+## 1.6.7
+
+* Added equivalent version of `mreqMsg` for `areq` and `wreq` correspondingly [#1628](https://github.com/yesodweb/yesod/pull/1628)
+
+## 1.6.6
+
+* Added `mreqMsg` for `mreq` functionality with a configurable MsgValueRequired [#1613](https://github.com/yesodweb/yesod/pull/1613)
+
+## 1.6.5
+
+* Add `.sr-only` to labels in `renderBootstrap3` when they are null.
+
+## 1.6.4
+
+* Make FormResult an instance of Eq
+
+## 1.6.3
+
+* make sure a select field does not lose the selected value even if a validation on the
+  field fails
+
+## 1.6.2
+
+* Move `addClass` from private/undocumented in `Yesod.Form.Bootstrap3` to `Yesod.Form.Functions` [#1510](https://github.com/yesodweb/yesod/pull/1510)
+* Add `Yesod.Form.Functions.removeClass` [#1510](https://github.com/yesodweb/yesod/pull/1510)
+* Changed `Textarea` to derive `IsString` [#1514](https://github.com/yesodweb/yesod/pull/1514)
+* Expose `selectFieldHelper` [#1530](https://github.com/yesodweb/yesod/pull/1530)
+
+## 1.6.1
+
+* Explicitly define `(<>)` in the `Semigroup` instance for `Enctype`
+
+## 1.6.0
+
+* Upgrade to yesod-core 1.6.0
+
 ## 1.4.16
 
 * Korean translation
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
 Form handling for Yesod, in the same style as formlets. See [the forms
 chapter](http://www.yesodweb.com/book/forms) of the Yesod book.
 
-This package provies a set of basic form inputs such as text, number, time,
+This package provides a set of basic form inputs such as text, number, time,
 checkbox, select, textarea, and etc. via `Yesod.Form.Fields` module.  Also,
 there is `Yesod.Form.Nic` module providing richtext field using Nic editor.
 However, this module is grandfathered now and Nic editor is not actively
diff --git a/Yesod/Form/Bootstrap3.hs b/Yesod/Form/Bootstrap3.hs
--- a/Yesod/Form/Bootstrap3.hs
+++ b/Yesod/Form/Bootstrap3.hs
@@ -1,6 +1,8 @@
+{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE QuasiQuotes #-}
 {-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TypeOperators #-}
+
 -- | Helper functions for creating forms when using <http://getbootstrap.com/ Bootstrap 3>.
 --
 
@@ -32,10 +34,8 @@
 import Control.Monad (liftM)
 import Data.Text (Text)
 import Data.String (IsString(..))
+import qualified Text.Blaze.Internal as Blaze
 import Yesod.Core
-
-import qualified Data.Text as T
-
 import Yesod.Form.Types
 import Yesod.Form.Functions
 
@@ -82,12 +82,6 @@
     where newAttrs = addClass "input-sm" (fsAttrs fs)
 
 
-addClass :: Text -> [(Text, Text)] -> [(Text, Text)]
-addClass klass []                    = [("class", klass)]
-addClass klass (("class", old):rest) = ("class", T.concat [old, " ", klass]) : rest
-addClass klass (other         :rest) = other : addClass klass rest
-
-
 -- | How many bootstrap grid columns should be taken (see
 -- 'BootstrapFormLayout').
 --
@@ -120,10 +114,10 @@
 toOffset (ColLg columns) = "col-lg-offset-" ++ show columns
 
 addGO :: BootstrapGridOptions -> BootstrapGridOptions -> BootstrapGridOptions
-addGO (ColXs a) (ColXs b) = ColXs (a+b)
-addGO (ColSm a) (ColSm b) = ColSm (a+b)
-addGO (ColMd a) (ColMd b) = ColMd (a+b)
-addGO (ColLg a) (ColLg b) = ColLg (a+b)
+addGO (ColXs a) (ColXs b) = ColXs (a + b)
+addGO (ColSm a) (ColSm b) = ColSm (a + b)
+addGO (ColMd a) (ColMd b) = ColMd (a + b)
+addGO (ColLg a) (ColLg b) = ColLg (a + b)
 addGO a b     | a > b = addGO b a
 addGO (ColXs a) other = addGO (ColSm a) other
 addGO (ColSm a) other = addGO (ColMd a) other
@@ -163,7 +157,7 @@
                 $case formLayout
                   $of BootstrapBasicForm
                     $if fvId view /= bootstrapSubmitId
-                      <label for=#{fvId view}>#{fvLabel view}
+                      <label :Blaze.null (fvLabel view):.sr-only for=#{fvId view}>#{fvLabel view}
                     ^{fvInput view}
                     ^{helpWidget view}
                   $of BootstrapInlineForm
@@ -173,7 +167,7 @@
                     ^{helpWidget view}
                   $of BootstrapHorizontalForm labelOffset labelSize inputOffset inputSize
                     $if fvId view /= bootstrapSubmitId
-                      <label .control-label .#{toOffset labelOffset} .#{toColumn labelSize} for=#{fvId view}>#{fvLabel view}
+                      <label :Blaze.null (fvLabel view):.sr-only .control-label .#{toOffset labelOffset} .#{toColumn labelSize} for=#{fvId view}>#{fvLabel view}
                       <div .#{toOffset inputOffset} .#{toColumn inputSize}>
                         ^{fvInput view}
                         ^{helpWidget view}
@@ -186,7 +180,7 @@
 
 
 -- | (Internal) Render a help widget for tooltips and errors.
-helpWidget :: FieldView site -> WidgetT site IO ()
+helpWidget :: FieldView site -> WidgetFor site ()
 helpWidget view = [whamlet|
     $maybe tt <- fvTooltip view
       <span .help-block>#{tt}
diff --git a/Yesod/Form/Fields.hs b/Yesod/Form/Fields.hs
--- a/Yesod/Form/Fields.hs
+++ b/Yesod/Form/Fields.hs
@@ -1,10 +1,13 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE CPP #-}
+{-# LANGUAGE TypeOperators #-}
+
 -- | Field functions allow you to easily create and validate forms, cleanly handling the uncertainty of parsing user input.
 --
 -- When possible, the field functions use a specific input type (e.g. "number"), allowing supporting browsers to validate the input before form submission. Browsers can also improve usability with this information; for example, mobile browsers might present a specialized keyboard for an input of type "email" or "number".
@@ -42,21 +45,30 @@
     , fileAFormOpt
       -- * Options
       -- $optionsOverview
+    , selectFieldHelper
     , selectField
     , selectFieldList
+    , selectFieldListGrouped
     , radioField
+    , radioField'
     , radioFieldList
+    , withRadioField
     , checkboxesField
+    , checkboxesField'
     , checkboxesFieldList
     , multiSelectField
     , multiSelectFieldList
     , Option (..)
     , OptionList (..)
     , mkOptionList
+    , mkOptionListGrouped
     , optionsPersist
     , optionsPersistKey
     , optionsPairs
+    , optionsPairsGrouped
     , optionsEnum
+    , colorField
+    , datetimeLocalField
     ) where
 
 import Yesod.Form.Types
@@ -67,7 +79,7 @@
 #define ToHtml ToMarkup
 #define toHtml toMarkup
 #define preEscapedText preEscapedToMarkup
-import Data.Time (Day, TimeOfDay(..))
+import Data.Time (Day, TimeOfDay(..), LocalTime (LocalTime))
 import qualified Text.Email.Validate as Email
 import Data.Text.Encoding (encodeUtf8, decodeUtf8With)
 import Data.Text.Encoding.Error (lenientDecode)
@@ -79,7 +91,7 @@
 import Database.Persist (Entity (..), SqlType (SqlString), PersistEntity, PersistQuery, PersistEntityBackend)
 #endif
 import Text.HTML.SanitizeXSS (sanitizeBalance)
-import Control.Monad (when, unless)
+import Control.Monad (when, unless, forM_)
 import Data.Either (partitionEithers)
 import Data.Maybe (listToMaybe, fromMaybe)
 
@@ -91,7 +103,8 @@
 import qualified Data.ByteString as S
 import qualified Data.ByteString.Lazy as L
 import Data.Text as T ( Text, append, concat, cons, head
-                      , intercalate, isPrefixOf, null, unpack, pack, splitOn
+                      , intercalate, isPrefixOf, null, unpack, pack
+                      , split, splitOn
                       )
 import qualified Data.Text as T (drop, dropWhile)
 import qualified Data.Text.Read
@@ -100,16 +113,20 @@
 import Yesod.Persist (selectList, Filter, SelectOpt, Key)
 import Control.Arrow ((&&&))
 
-import Control.Applicative ((<$>), (<|>))
+import Control.Applicative ((<|>))
 
 import Data.Attoparsec.Text (Parser, char, string, digit, skipSpace, endOfInput, parseOnly)
 
 import Yesod.Persist.Core
 
-#if !MIN_VERSION_base(4,8,0)
-import Data.Monoid
-#endif
+import Data.String (IsString)
 
+
+import Data.Char (isHexDigit)
+
+{-# DEPRECATED radioField "This function seems to have a bug (label could not be found with byLabel algorithm). Use radioField' instead." #-}
+{-# DEPRECATED checkboxesField "This function seems to have a bug (label could not be found with byLabel algorithm). Use checkboxesField' instead." #-}
+
 defaultFormMessage :: FormMessage -> Text
 defaultFormMessage = englishFormMessage
 
@@ -161,24 +178,25 @@
     }
   where showVal = either id (pack . show)
 
--- | An alias for 'timeFieldTypeText'.
+-- | An alias for 'timeFieldTypeTime'.
 timeField :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m TimeOfDay
-timeField = timeFieldTypeText
-{-# DEPRECATED timeField "'timeField' currently defaults to an input of type=\"text\". In the next major release, it will default to type=\"time\". To opt in to the new functionality, use 'timeFieldTypeTime'. To keep the existing behavior, use 'timeFieldTypeText'. See 'https://github.com/yesodweb/yesod/pull/874' for details." #-}
+timeField = timeFieldTypeTime
 
 -- | Creates an input with @type="time"@. <http://caniuse.com/#search=time%20input%20type Browsers not supporting this type> will fallback to a text field, and Yesod will parse the time as described in 'timeFieldTypeText'.
--- 
+--
 -- Add the @time@ package and import the "Data.Time.LocalTime" module to use this function.
 --
--- Since 1.4.2
-timeFieldTypeTime :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m TimeOfDay  
+-- @since 1.4.2
+timeFieldTypeTime :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m TimeOfDay
 timeFieldTypeTime = timeFieldOfType "time"
 
 -- | Creates an input with @type="text"@, parsing the time from an [H]H:MM[:SS] format, with an optional AM or PM (if not given, AM is assumed for compatibility with the 24 hour clock system).
--- 
+--
+-- This function exists for backwards compatibility with the old implementation of 'timeField', which used to use @type="text"@. Consider using 'timeField' or 'timeFieldTypeTime' for improved UX and validation from the browser.
+--
 -- Add the @time@ package and import the "Data.Time.LocalTime" module to use this function.
 --
--- Since 1.4.2
+-- @since 1.4.2
 timeFieldTypeText :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m TimeOfDay
 timeFieldTypeText = timeFieldOfType "text"
 
@@ -211,12 +229,12 @@
   where showVal = either id (pack . renderHtml)
 
 -- | A newtype wrapper around a 'Text' whose 'ToMarkup' instance converts newlines to HTML @\<br>@ tags.
--- 
+--
 -- (When text is entered into a @\<textarea>@, newline characters are used to separate lines.
 -- If this text is then placed verbatim into HTML, the lines won't be separated, thus the need for replacing with @\<br>@ tags).
 -- If you don't need this functionality, simply use 'unTextarea' to access the raw text.
 newtype Textarea = Textarea { unTextarea :: Text }
-    deriving (Show, Read, Eq, PersistField, Ord, ToJSON, FromJSON)
+    deriving (Show, Read, Eq, PersistField, Ord, ToJSON, FromJSON, IsString)
 instance PersistFieldSql Textarea where
     sqlType _ = SqlString
 instance ToHtml Textarea where
@@ -325,7 +343,7 @@
   where
     hour = do
         x <- digit
-        y <- (return Control.Applicative.<$> digit) <|> return []
+        y <- (return <$> digit) <|> return []
         let xy = x : y
         let i = read xy
         if i < 0 || i >= 24
@@ -340,7 +358,7 @@
         if i < 0 || i >= 60
             then fail $ show $ msg $ pack xy
             else return $ fromIntegral (i :: Int)
-            
+
 -- | Creates an input with @type="email"@. Yesod will validate the email's correctness according to RFC5322 and canonicalize it by removing comments and whitespace (see "Text.Email.Validate").
 emailField :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m Text
 emailField = Field
@@ -358,7 +376,7 @@
 
 -- | Creates an input with @type="email"@ with the <http://w3c.github.io/html/sec-forms.html#the-multiple-attribute multiple> attribute; browsers might implement this as taking a comma separated list of emails. Each email address is validated as described in 'emailField'.
 --
--- Since 1.3.7
+-- @since 1.3.7
 multiEmailField :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m [Text]
 multiEmailField = Field
     { fieldParse = parseHelper $
@@ -420,15 +438,23 @@
 -- > areq (selectFieldList [("Value 1" :: Text, "value1"),("Value 2", "value2")]) "Which value?" Nothing
 selectFieldList :: (Eq a, RenderMessage site FormMessage, RenderMessage site msg)
                 => [(msg, a)]
-                -> Field (HandlerT site IO) a
+                -> Field (HandlerFor site) a
 selectFieldList = selectField . optionsPairs
 
--- | Creates a @\<select>@ tag for selecting one option. Example usage:
+-- | Creates a @\<select>@ tag with @\<optgroup>@s for selecting one option.
 --
+-- @since 1.7.0
+selectFieldListGrouped :: (Eq a, RenderMessage site FormMessage, RenderMessage site msg)
+                => [(msg, [(msg, a)])]
+                -> Field (HandlerFor site) a
+selectFieldListGrouped = selectField . optionsPairsGrouped
+
+-- | Creates a @\<select>@ tag with optional @\<optgroup>@s for selecting one option. Example usage:
+--
 -- > areq (selectField $ optionsPairs [(MsgValue1, "value1"),(MsgValue2, "value2")]) "Which value?" Nothing
 selectField :: (Eq a, RenderMessage site FormMessage)
-            => HandlerT site IO (OptionList a)
-            -> Field (HandlerT site IO) a
+            => HandlerFor site (OptionList a)
+            -> Field (HandlerFor site) a
 selectField = selectFieldHelper
     (\theId name attrs inside -> [whamlet|
 $newline never
@@ -442,17 +468,20 @@
 $newline never
 <option value=#{value} :isSel:selected>#{text}
 |]) -- inside
+    (Just $ \label -> [whamlet|
+<optgroup label=#{label}>
+|]) -- group label
 
 -- | Creates a @\<select>@ tag for selecting multiple options.
 multiSelectFieldList :: (Eq a, RenderMessage site msg)
                      => [(msg, a)]
-                     -> Field (HandlerT site IO) [a]
+                     -> Field (HandlerFor site) [a]
 multiSelectFieldList = multiSelectField . optionsPairs
 
 -- | Creates a @\<select>@ tag for selecting multiple options.
 multiSelectField :: Eq a
-                 => HandlerT site IO (OptionList a)
-                 -> Field (HandlerT site IO) [a]
+                 => HandlerFor site (OptionList a)
+                 -> Field (HandlerFor site) [a]
 multiSelectField ioptlist =
     Field parse view UrlEncoded
   where
@@ -478,18 +507,18 @@
 -- | Creates an input with @type="radio"@ for selecting one option.
 radioFieldList :: (Eq a, RenderMessage site FormMessage, RenderMessage site msg)
                => [(msg, a)]
-               -> Field (HandlerT site IO) a
+               -> Field (HandlerFor site) a
 radioFieldList = radioField . optionsPairs
 
 -- | Creates an input with @type="checkbox"@ for selecting multiple options.
 checkboxesFieldList :: (Eq a, RenderMessage site msg) => [(msg, a)]
-                     -> Field (HandlerT site IO) [a]
+                     -> Field (HandlerFor site) [a]
 checkboxesFieldList = checkboxesField . optionsPairs
 
 -- | Creates an input with @type="checkbox"@ for selecting multiple options.
 checkboxesField :: Eq a
-                 => HandlerT site IO (OptionList a)
-                 -> Field (HandlerT site IO) [a]
+                 => HandlerFor site (OptionList a)
+                 -> Field (HandlerFor site) [a]
 checkboxesField ioptlist = (multiSelectField ioptlist)
     { fieldView =
         \theId name attrs val _isReq -> do
@@ -504,35 +533,104 @@
                             #{optionDisplay opt}
                 |]
     }
+
+-- | Creates an input with @type="checkbox"@ for selecting multiple options.
+checkboxesField' :: Eq a
+                 => HandlerFor site (OptionList a)
+                 -> Field (HandlerFor site) [a]
+checkboxesField' ioptlist = (multiSelectField ioptlist)
+    { fieldView =
+        \theId name attrs val _isReq -> do
+            opts <- olOptions <$> handlerToWidget ioptlist
+            let optselected (Left _) _ = False
+                optselected (Right vals) opt = optionInternalValue opt `elem` vals
+            [whamlet|
+                <span ##{theId}>
+                    $forall opt <- opts
+                        <input id=#{theId}-#{optionExternalValue opt} type=checkbox name=#{name} value=#{optionExternalValue opt} *{attrs} :optselected val opt:checked>
+                        <label for=#{theId}-#{optionExternalValue opt}>
+                            #{optionDisplay opt}
+                |]
+    }
+
+
 -- | Creates an input with @type="radio"@ for selecting one option.
 radioField :: (Eq a, RenderMessage site FormMessage)
-           => HandlerT site IO (OptionList a)
-           -> Field (HandlerT site IO) a
-radioField = selectFieldHelper
-    (\theId _name _attrs inside -> [whamlet|
+           => HandlerFor site (OptionList a)
+           -> Field (HandlerFor site) a
+radioField = withRadioField
+    (\theId optionWidget -> [whamlet|
 $newline never
-<div ##{theId}>^{inside}
+<div .radio>
+    <label for=#{theId}-none>
+        <div>
+            ^{optionWidget}
+            _{MsgSelectNone}
 |])
-    (\theId name isSel -> [whamlet|
+    (\theId value _isSel text optionWidget -> [whamlet|
 $newline never
-<label .radio for=#{theId}-none>
-    <div>
-        <input id=#{theId}-none type=radio name=#{name} value=none :isSel:checked>
-        _{MsgSelectNone}
+<div .radio>
+    <label for=#{theId}-#{value}>
+        <div>
+            ^{optionWidget}
+            \#{text}
 |])
-    (\theId name attrs value isSel text -> [whamlet|
+
+
+-- | Creates an input with @type="radio"@ for selecting one option.
+--
+--   @since 1.7.8
+radioField' :: (Eq a, RenderMessage site FormMessage)
+           => HandlerFor site (OptionList a)
+           -> Field (HandlerFor site) a
+radioField' = withRadioField
+    (\theId optionWidget -> [whamlet|
 $newline never
-<label .radio for=#{theId}-#{value}>
-    <div>
-        <input id=#{theId}-#{value} type=radio name=#{name} value=#{value} :isSel:checked *{attrs}>
-        \#{text}
+<.radio>
+  ^{optionWidget}
+  <label for=#{theId}-none>
+    _{MsgSelectNone}
 |])
+    (\theId value _isSel text optionWidget -> [whamlet|
+$newline never
+<.radio>
+  ^{optionWidget}
+  <label for=#{theId}-#{value}>
+    \#{text}
+|])
 
+-- | Allows the user to place the option radio widget somewhere in
+--   the template.
+--   For example: If you want a table of radio options to select.
+--   'radioField' is an example on how to use this function.
+--
+--   @since 1.7.2
+withRadioField :: (Eq a, RenderMessage site FormMessage)
+           => (Text -> WidgetFor site ()-> WidgetFor site ()) -- ^ nothing case for mopt
+           -> (Text ->  Text -> Bool -> Text -> WidgetFor site () -> WidgetFor site ()) -- ^ cases for values
+           -> HandlerFor site (OptionList a)
+           -> Field (HandlerFor site) a
+withRadioField nothingFun optFun =
+  selectFieldHelper outside onOpt inside Nothing
+  where
+    outside theId _name _attrs inside' = [whamlet|
+$newline never
+<div ##{theId}>^{inside'}
+|]
+    onOpt theId name isSel = nothingFun theId $ [whamlet|
+$newline never
+<input id=#{theId}-none type=radio name=#{name} value=none :isSel:checked>
+|]
+    inside theId name attrs value isSel display =
+       optFun theId value isSel display [whamlet|
+<input id=#{theId}-#{(value)} type=radio name=#{name} value=#{(value)} :isSel:checked *{attrs}>
+|]
+
 -- | Creates a group of radio buttons to answer the question given in the message. Radio buttons are used to allow differentiating between an empty response (@Nothing@) and a no response (@Just False@). Consider using the simpler 'checkBoxField' if you don't need to make this distinction.
 --
 -- If this field is optional, the first radio button is labeled "\<None>", the second \"Yes" and the third \"No".
 --
--- If this field is required, the first radio button is labeled \"Yes" and the second \"No". 
+-- If this field is required, the first radio button is labeled \"Yes" and the second \"No".
 --
 -- (Exact label titles will depend on localization).
 boolField :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m Bool
@@ -566,7 +664,7 @@
       t -> Left $ SomeMessage $ MsgInvalidBool t
     showVal = either (\_ -> False)
 
--- | Creates an input with @type="checkbox"@. 
+-- | Creates an input with @type="checkbox"@.
 --   While the default @'boolField'@ implements a radio button so you
 --   can differentiate between an empty response (@Nothing@) and a no
 --   response (@Just False@), this simpler checkbox field returns an empty
@@ -594,15 +692,31 @@
         showVal = either (\_ -> False)
 
 -- | A structure holding a list of options. Typically you can use a convenience function like 'mkOptionList' or 'optionsPairs' instead of creating this directly.
-data OptionList a = OptionList
+--
+-- Extended by 'OptionListGrouped' in 1.7.0.
+data OptionList a
+  = OptionList
     { olOptions :: [Option a]
     , olReadExternal :: Text -> Maybe a -- ^ A function mapping from the form's value ('optionExternalValue') to the selected Haskell value ('optionInternalValue').
     }
+  | OptionListGrouped
+    { olOptionsGrouped :: [(Text, [Option a])]
+    , olReadExternalGrouped :: Text -> Maybe a -- ^ A function mapping from the form's value ('optionExternalValue') to the selected Haskell value ('optionInternalValue').
+    }
 
--- | Since 1.4.6
+-- | Convert grouped 'OptionList' to a normal one.
+--
+-- @since 1.7.0
+flattenOptionList :: OptionList a -> OptionList a
+flattenOptionList (OptionListGrouped os re) = OptionList (concatMap snd os) re
+flattenOptionList ol = ol
+
+-- | @since 1.4.6
 instance Functor OptionList where
-    fmap f (OptionList options readExternal) = 
+    fmap f (OptionList options readExternal) =
       OptionList ((fmap.fmap) f options) (fmap f . readExternal)
+    fmap f (OptionListGrouped options readExternal) =
+      OptionListGrouped (map (\(g, os) -> (g, (fmap.fmap) f os)) options) (fmap f . readExternal)
 
 -- | Creates an 'OptionList', using a 'Map' to implement the 'olReadExternal' function.
 mkOptionList :: [Option a] -> OptionList a
@@ -611,13 +725,22 @@
     , olReadExternal = flip Map.lookup $ Map.fromList $ map (optionExternalValue &&& optionInternalValue) os
     }
 
+-- | Creates an 'OptionList', using a 'Map' to implement the 'olReadExternalGrouped' function.
+--
+-- @since 1.7.0
+mkOptionListGrouped :: [(Text, [Option a])] -> OptionList a
+mkOptionListGrouped os = OptionListGrouped
+    { olOptionsGrouped = os
+    , olReadExternalGrouped = flip Map.lookup $ Map.fromList $ map (optionExternalValue &&& optionInternalValue) $ concatMap snd os
+    }
+
 data Option a = Option
     { optionDisplay :: Text -- ^ The user-facing label.
     , optionInternalValue :: a -- ^ The Haskell value being selected.
     , optionExternalValue :: Text -- ^ The representation of this value stored in the form.
     }
 
--- | Since 1.4.6
+-- | @since 1.4.6
 instance Functor Option where
     fmap f (Option display internal external) = Option display (f internal) external
 
@@ -633,6 +756,30 @@
                  }
   return $ mkOptionList (zipWith mkOption [1 :: Int ..] opts)
 
+-- | Creates an 'OptionList' from a list of (display-value, internal value) pairs.
+--
+-- @since 1.7.0
+optionsPairsGrouped
+  :: forall m msg a. (MonadHandler m, RenderMessage (HandlerSite m) msg)
+  => [(msg, [(msg, a)])] -> m (OptionList a)
+optionsPairsGrouped opts = do
+  mr <- getMessageRender
+  let mkOption (external, (display, internal)) =
+          Option { optionDisplay       = mr display
+                 , optionInternalValue = internal
+                 , optionExternalValue = pack $ show external
+                 }
+      opts' = enumerateSublists opts :: [(msg, [(Int, (msg, a))])]
+      opts'' = map (\(x, ys) -> (mr x, map mkOption ys)) opts'
+  return $ mkOptionListGrouped opts''
+
+-- | Helper to enumerate sublists with one consecutive index.
+enumerateSublists :: forall a b. [(a, [b])] -> [(a, [(Int, b)])]
+enumerateSublists xss =
+  let yss :: [(Int, (a, [b]))]
+      yss = snd $ foldl (\(i, res) xs -> (i + (length.snd) xs, res ++ [(i, xs)])) (1, []) xss
+   in map (\(i, (x, ys)) -> (x, zip [i :: Int ..] ys)) yss
+
 -- | Creates an 'OptionList' from an 'Enum', using its 'Show' instance for the user-facing value.
 optionsEnum :: (MonadHandler m, Show a, Enum a, Bounded a) => m (OptionList a)
 optionsEnum = optionsPairs $ map (\x -> (pack $ show x, x)) [minBound..maxBound]
@@ -663,7 +810,7 @@
                => [Filter a]
                -> [SelectOpt a]
                -> (a -> msg)
-               -> HandlerT site IO (OptionList (Entity a))
+               -> HandlerFor site (OptionList (Entity a))
 #else
 optionsPersist :: ( YesodPersist site, PersistEntity a
                   , PersistQuery (PersistEntityBackend a)
@@ -674,7 +821,7 @@
                => [Filter a]
                -> [SelectOpt a]
                -> (a -> msg)
-               -> HandlerT site IO (OptionList (Entity a))
+               -> HandlerFor site (OptionList (Entity a))
 #endif
 optionsPersist filts ords toDisplay = fmap mkOptionList $ do
     mr <- getMessageRender
@@ -688,7 +835,7 @@
 -- | An alternative to 'optionsPersist' which returns just the 'Key' instead of
 -- the entire 'Entity'.
 --
--- Since 1.3.2
+-- @since 1.3.2
 #if MIN_VERSION_persistent(2,5,0)
 optionsPersistKey
   :: (YesodPersist site
@@ -701,7 +848,7 @@
   => [Filter a]
   -> [SelectOpt a]
   -> (a -> msg)
-  -> HandlerT site IO (OptionList (Key a))
+  -> HandlerFor site (OptionList (Key a))
 #else
 optionsPersistKey
   :: (YesodPersist site
@@ -714,7 +861,7 @@
   => [Filter a]
   -> [SelectOpt a]
   -> (a -> msg)
-  -> HandlerT site IO (OptionList (Key a))
+  -> HandlerFor site (OptionList (Key a))
 #endif
 
 optionsPersistKey filts ords toDisplay = fmap mkOptionList $ do
@@ -726,32 +873,39 @@
         , optionExternalValue = toPathPiece key
         }) pairs
 
+-- |
+-- A helper function for constucting 'selectField's with optional option groups. You may want to use this when you define your custom 'selectField's or 'radioField's.
+--
+-- @since 1.6.2
 selectFieldHelper
         :: (Eq a, RenderMessage site FormMessage)
-        => (Text -> Text -> [(Text, Text)] -> WidgetT site IO () -> WidgetT site IO ())
-        -> (Text -> Text -> Bool -> WidgetT site IO ())
-        -> (Text -> Text -> [(Text, Text)] -> Text -> Bool -> Text -> WidgetT site IO ())
-        -> HandlerT site IO (OptionList a)
-        -> Field (HandlerT site IO) a
-selectFieldHelper outside onOpt inside opts' = Field
+        => (Text -> Text -> [(Text, Text)] -> WidgetFor site () -> WidgetFor site ()) -- ^ Outermost part of the field
+        -> (Text -> Text -> Bool -> WidgetFor site ()) -- ^ An option for None if the field is optional
+        -> (Text -> Text -> [(Text, Text)] -> Text -> Bool -> Text -> WidgetFor site ()) -- ^ Other options
+        -> (Maybe (Text -> WidgetFor site ())) -- ^ Group headers placed inbetween options
+        -> HandlerFor site (OptionList a)
+        -> Field (HandlerFor site) a
+selectFieldHelper outside onOpt inside grpHdr opts' = Field
     { fieldParse = \x _ -> do
-        opts <- opts'
+        opts <- fmap flattenOptionList opts'
         return $ selectParser opts x
     , fieldView = \theId name attrs val isReq -> do
-        opts <- fmap olOptions $ handlerToWidget opts'
         outside theId name attrs $ do
-            unless isReq $ onOpt theId name $ not $ render opts val `elem` map optionExternalValue opts
-            flip mapM_ opts $ \opt -> inside
-                theId
-                name
-                ((if isReq then (("required", "required"):) else id) attrs)
-                (optionExternalValue opt)
-                ((render opts val) == optionExternalValue opt)
-                (optionDisplay opt)
+          optsFlat <- fmap (olOptions.flattenOptionList) $ handlerToWidget opts'
+          unless isReq $ onOpt theId name $ render optsFlat val `notElem` map optionExternalValue optsFlat
+          opts'' <- handlerToWidget opts'
+          case opts'' of
+            OptionList{} -> constructOptions theId name attrs val isReq optsFlat
+            OptionListGrouped{olOptionsGrouped=grps} -> do
+                  forM_ grps $ \(grp, opts) -> do
+                    case grpHdr of
+                      Just hdr -> hdr grp
+                      Nothing -> return ()
+                    constructOptions theId name attrs val isReq opts
     , fieldEnctype = UrlEncoded
     }
   where
-    render _ (Left _) = ""
+    render _ (Left x) = x
     render opts (Right a) = maybe "" optionExternalValue $ listToMaybe $ filter ((== a) . optionInternalValue) opts
     selectParser _ [] = Right Nothing
     selectParser opts (s:_) = case s of
@@ -760,6 +914,14 @@
             x -> case olReadExternal opts x of
                     Nothing -> Left $ SomeMessage $ MsgInvalidEntry x
                     Just y -> Right $ Just y
+    constructOptions theId name attrs val isReq opts =
+      forM_ opts $ \opt -> inside
+                           theId
+                           name
+                           ((if isReq then (("required", "required"):) else id) attrs)
+                           (optionExternalValue opt)
+                           (render opts val == optionExternalValue opt)
+                           (optionDisplay opt)
 
 -- | Creates an input with @type="file"@.
 fileField :: Monad m
@@ -856,11 +1018,52 @@
                            then "-0." `T.append` (T.drop 2 t1)
                            else t1
 
-  where t1 = T.dropWhile ((==) ' ') t0
+  where t1 = T.dropWhile (== ' ') t0
 
 -- $optionsOverview
 -- These functions create inputs where one or more options can be selected from a list.
--- 
+--
 -- The basic datastructure used is an 'Option', which combines a user-facing display value, the internal Haskell value being selected, and an external 'Text' stored as the @value@ in the form (used to map back to the internal value). A list of these, together with a function mapping from an external value back to a Haskell value, form an 'OptionList', which several of these functions take as an argument.
--- 
+--
 -- Typically, you won't need to create an 'OptionList' directly and can instead make one with functions like 'optionsPairs' or 'optionsEnum'. Alternatively, you can use functions like 'selectFieldList', which use their @[(msg, a)]@ parameter to create an 'OptionList' themselves.
+
+-- | Creates an input with @type="color"@.
+--   The input value must be provided in hexadecimal format #rrggbb.
+--
+-- @since 1.7.1
+colorField :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m Text
+colorField = Field
+    { fieldParse = parseHelper $ \s ->
+        if isHexColor $ unpack s then Right s
+        else Left $ MsgInvalidHexColorFormat s
+    , fieldView = \theId name attrs val _ -> [whamlet|
+$newline never
+<input ##{theId} name=#{name} *{attrs} type=color value=#{either id id val}>
+|]
+    , fieldEnctype = UrlEncoded
+    }
+  where
+      isHexColor :: String -> Bool
+      isHexColor ['#',a,b,c,d,e,f] = all isHexDigit [a,b,c,d,e,f]
+      isHexColor _ = False
+
+-- | Creates an input with @type="datetime-local"@.
+--   The input value must be provided in YYYY-MM-DD(T| )HH:MM[:SS] format.
+--
+-- @since 1.7.6
+datetimeLocalField :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m LocalTime
+datetimeLocalField = Field
+    { fieldParse = parseHelper $ \s -> case T.split (\c -> (c == 'T') || (c == ' ')) s of
+        [d,t] -> do
+            day <- parseDate $ unpack d
+            time <- parseTime t
+            Right $ LocalTime day time
+        _ -> Left $ MsgInvalidDatetimeFormat s
+    , fieldView = \theId name attrs val isReq -> [whamlet|
+$newline never
+<input type=datetime-local ##{theId} name=#{name} value=#{showVal val} *{attrs} :isReq:required>
+|]
+    , fieldEnctype = UrlEncoded
+    }
+  where
+    showVal = either id (pack . show)
diff --git a/Yesod/Form/Functions.hs b/Yesod/Form/Functions.hs
--- a/Yesod/Form/Functions.hs
+++ b/Yesod/Form/Functions.hs
@@ -1,10 +1,12 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
 {-# LANGUAGE TupleSections #-}
 {-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE CPP #-}
+{-# LANGUAGE TypeOperators #-}
+
 module Yesod.Form.Functions
     ( -- * Running in MForm monad
       newFormIdent
@@ -18,10 +20,13 @@
     , wFormToMForm
       -- * Fields to Forms
     , wreq
+    , wreqMsg
     , wopt
     , mreq
+    , mreqMsg
     , mopt
     , areq
+    , areqMsg
     , aopt
       -- * Run a form
     , runFormPost
@@ -51,10 +56,13 @@
     , parseHelper
     , parseHelperGen
     , convertField
+    , addClass
+    , removeClass
     ) where
 
 import Yesod.Form.Types
 import Data.Text (Text, pack)
+import qualified Data.Text as T
 import Control.Arrow (second)
 import Control.Monad.Trans.Class
 import Control.Monad.Trans.RWS (ask, get, put, runRWST, tell, evalRWST, local, mapRWST)
@@ -66,7 +74,6 @@
 #define toHtml toMarkup
 import Yesod.Core
 import Network.Wai (requestMethod)
-import Data.Monoid (mempty, (<>))
 import Data.Maybe (listToMaybe, fromMaybe)
 import qualified Data.Map as Map
 import qualified Data.Text.Encoding as TE
@@ -120,8 +127,24 @@
      -> FieldSettings site  -- ^ settings for this field
      -> Maybe a             -- ^ optional default value
      -> WForm m (FormResult a)
-wreq f fs = mFormToWForm . mreq f fs
+wreq f fs = wreqMsg f fs MsgValueRequired
 
+-- | Same as @wreq@ but with your own message to be rendered in case the value
+-- is not provided.
+--
+-- This is useful when you have several required fields on the page and you
+-- want to differentiate between which fields were left blank. Otherwise the
+-- user sees "Value is required" multiple times, which is ambiguous.
+--
+-- @since 1.6.7
+wreqMsg :: (RenderMessage site msg, HandlerSite m ~ site, MonadHandler m)
+        => Field m a           -- ^ form field
+        -> FieldSettings site  -- ^ settings for this field
+        -> msg                 -- ^ message to use in case value is Nothing
+        -> Maybe a             -- ^ optional default value
+        -> WForm m (FormResult a)
+wreqMsg f fs msg = mFormToWForm . mreqMsg f fs msg
+
 -- | Converts a form field into monadic form 'WForm'. This field is optional,
 -- i.e.  if filled in, it returns 'Just a', if left empty, it returns
 -- 'Nothing'.  Arguments are the same as for 'wreq' (apart from type of default
@@ -170,8 +193,25 @@
      -> FieldSettings site  -- ^ settings for this field
      -> Maybe a             -- ^ optional default value
      -> MForm m (FormResult a, FieldView site)
-mreq field fs mdef = mhelper field fs mdef (\m l -> FormFailure [renderMessage m l MsgValueRequired]) FormSuccess True
+mreq field fs mdef = mreqMsg field fs MsgValueRequired mdef
 
+-- | Same as @mreq@ but with your own message to be rendered in case the value
+-- is not provided.
+--
+-- This is useful when you have several required fields on the page and you
+-- want to differentiate between which fields were left blank. Otherwise the
+-- user sees "Value is required" multiple times, which is ambiguous.
+--
+-- @since 1.6.6
+mreqMsg :: (RenderMessage site msg, HandlerSite m ~ site, MonadHandler m)
+        => Field m a           -- ^ form field
+        -> FieldSettings site  -- ^ settings for this field
+        -> msg                 -- ^ Message to use in case value is Nothing
+        -> Maybe a             -- ^ optional default value
+        -> MForm m (FormResult a, FieldView site)
+mreqMsg field fs msg mdef = mhelper field fs mdef formFailure FormSuccess True
+  where formFailure m l = FormFailure [renderMessage m l msg]
+
 -- | Converts a form field into monadic form. This field is optional, i.e.
 -- if filled in, it returns 'Just a', if left empty, it returns 'Nothing'.
 -- Arguments are the same as for 'mreq' (apart from type of default value).
@@ -226,12 +266,28 @@
 
 -- | Applicative equivalent of 'mreq'.
 areq :: (RenderMessage site FormMessage, HandlerSite m ~ site, MonadHandler m)
-     => Field m a
-     -> FieldSettings site
-     -> Maybe a
+     => Field m a           -- ^ form field
+     -> FieldSettings site  -- ^ settings for this field
+     -> Maybe a             -- ^ optional default value
      -> AForm m a
-areq a b = formToAForm . liftM (second return) . mreq a b
+areq f fs = areqMsg f fs MsgValueRequired
 
+-- | Same as @areq@ but with your own message to be rendered in case the value
+-- is not provided.
+--
+-- This is useful when you have several required fields on the page and you
+-- want to differentiate between which fields were left blank. Otherwise the
+-- user sees "Value is required" multiple times, which is ambiguous.
+--
+-- @since 1.6.7
+areqMsg :: (RenderMessage site msg, HandlerSite m ~ site, MonadHandler m)
+        => Field m a           -- ^ form field
+        -> FieldSettings site  -- ^ settings for this field
+        -> msg                 -- ^ message to use in case value is Nothing
+        -> Maybe a             -- ^ optional default value
+        -> AForm m a
+areqMsg f fs msg = formToAForm . liftM (second return) . mreqMsg f fs msg
+
 -- | Applicative equivalent of 'mopt'.
 aopt :: MonadHandler m
      => Field m a
@@ -273,7 +329,7 @@
     let tokenKey = defaultCsrfParamName
     let token =
             case reqToken req of
-                Nothing -> Data.Monoid.mempty
+                Nothing -> mempty
                 Just n -> [shamlet|<input type=hidden name=#{tokenKey} value=#{n}>|]
     m <- getYesod
     langs <- languages
@@ -385,8 +441,8 @@
 identifyForm
   :: Monad m
   => Text -- ^ Form identification string.
-  -> (Html -> MForm m (FormResult a, WidgetT (HandlerSite m) IO ()))
-  -> (Html -> MForm m (FormResult a, WidgetT (HandlerSite m) IO ()))
+  -> (Html -> MForm m (FormResult a, WidgetFor (HandlerSite m) ()))
+  -> (Html -> MForm m (FormResult a, WidgetFor (HandlerSite m) ()))
 identifyForm identVal form = \fragment -> do
     -- Create hidden <input>.
     let fragment' =
@@ -418,7 +474,7 @@
 type FormRender m a =
        AForm m a
     -> Html
-    -> MForm m (FormResult a, WidgetT (HandlerSite m) IO ())
+    -> MForm m (FormResult a, WidgetFor (HandlerSite m) ())
 
 renderTable, renderDivs, renderDivsNoLabels :: Monad m => FormRender m a
 -- | Render a form into a series of tr tags. Note that, in order to allow
@@ -615,3 +671,33 @@
   fParse' ts = fmap (fmap (fmap to)) . fParse ts
   fView' ti tn at ei = fView ti tn at (fmap from ei)
   in Field fParse' fView' fEnctype
+
+-- | Removes a CSS class from the 'fsAttrs' in a 'FieldSettings'.
+--
+-- ==== __Examples__
+--
+-- >>> removeClass "form-control" [("class","form-control login-form"),("id","home-login")]
+-- [("class","  login-form"),("id","home-login")]
+--
+-- @since 1.6.2
+removeClass :: Text -- ^ The class to remove
+            -> [(Text, Text)] -- ^ List of existing 'fsAttrs'
+            -> [(Text, Text)]
+removeClass _     []                    = []
+removeClass klass (("class", old):rest) = ("class", T.replace klass " " old) : rest
+removeClass klass (other         :rest) = other : removeClass klass rest
+
+-- | Adds a CSS class to the 'fsAttrs' in a 'FieldSettings'.
+--
+-- ==== __Examples__
+--
+-- >>> addClass "login-form" [("class", "form-control"), ("id", "home-login")]
+-- [("class","form-control login-form"),("id","home-login")]
+--
+-- @since 1.6.2
+addClass :: Text -- ^ The class to add
+         -> [(Text, Text)] -- ^ List of existing 'fsAttrs'
+         -> [(Text, Text)]
+addClass klass []                    = [("class", klass)]
+addClass klass (("class", old):rest) = ("class", T.concat [old, " ", klass]) : rest
+addClass klass (other         :rest) = other : addClass klass rest
diff --git a/Yesod/Form/I18n/Chinese.hs b/Yesod/Form/I18n/Chinese.hs
--- a/Yesod/Form/I18n/Chinese.hs
+++ b/Yesod/Form/I18n/Chinese.hs
@@ -1,12 +1,12 @@
 {-# LANGUAGE OverloadedStrings #-}
+
 module Yesod.Form.I18n.Chinese where
 
 import Yesod.Form.Types (FormMessage (..))
-import Data.Monoid (mappend)
 import Data.Text (Text)
 
 chineseFormMessage :: FormMessage -> Text
-chineseFormMessage (MsgInvalidInteger t) = "无效的整数: " `Data.Monoid.mappend` t
+chineseFormMessage (MsgInvalidInteger t) = "无效的整数: " `mappend` t
 chineseFormMessage (MsgInvalidNumber t) = "无效的数字: " `mappend` t
 chineseFormMessage (MsgInvalidEntry t) = "无效的条目: " `mappend` t
 chineseFormMessage MsgInvalidTimeFormat = "无效的时间, 必须符合HH:MM[:SS]格式"
@@ -24,3 +24,5 @@
 chineseFormMessage MsgBoolYes = "是"
 chineseFormMessage MsgBoolNo = "否"
 chineseFormMessage MsgDelete = "删除?"
+chineseFormMessage (MsgInvalidHexColorFormat t) = "颜色无效，必须为 #rrggbb 十六进制格式: " `mappend` t
+chineseFormMessage (MsgInvalidDatetimeFormat t) = "日期時間無效，必須採用 YYYY-MM-DD(T| )HH:MM[:SS] 格式： " `mappend` t
diff --git a/Yesod/Form/I18n/Czech.hs b/Yesod/Form/I18n/Czech.hs
--- a/Yesod/Form/I18n/Czech.hs
+++ b/Yesod/Form/I18n/Czech.hs
@@ -1,12 +1,12 @@
 {-# LANGUAGE OverloadedStrings #-}
+
 module Yesod.Form.I18n.Czech where
 
 import Yesod.Form.Types (FormMessage (..))
-import Data.Monoid (mappend)
 import Data.Text (Text)
 
 czechFormMessage :: FormMessage -> Text
-czechFormMessage (MsgInvalidInteger t) = "Neplatné celé číslo: " `Data.Monoid.mappend` t
+czechFormMessage (MsgInvalidInteger t) = "Neplatné celé číslo: " `mappend` t
 czechFormMessage (MsgInvalidNumber t) = "Neplatné číslo: " `mappend` t
 czechFormMessage (MsgInvalidEntry t) = "Neplatná položka: " `mappend` t
 czechFormMessage MsgInvalidTimeFormat = "Neplatný čas, musí být ve formátu HH:MM[:SS]"
@@ -24,3 +24,5 @@
 czechFormMessage MsgBoolYes = "Ano"
 czechFormMessage MsgBoolNo = "Ne"
 czechFormMessage MsgDelete = "Smazat?"
+czechFormMessage (MsgInvalidHexColorFormat t) = "Neplatná barva, musí být v #rrggbb hexadecimálním formátu: " `mappend` t
+czechFormMessage (MsgInvalidDatetimeFormat t) = "Neplatné datum a čas, musí být ve formátu YYYY-MM-DD(T| )HH:MM[:SS]: " `mappend` t
diff --git a/Yesod/Form/I18n/Dutch.hs b/Yesod/Form/I18n/Dutch.hs
--- a/Yesod/Form/I18n/Dutch.hs
+++ b/Yesod/Form/I18n/Dutch.hs
@@ -1,12 +1,12 @@
 {-# LANGUAGE OverloadedStrings #-}
+
 module Yesod.Form.I18n.Dutch where
 
 import Yesod.Form.Types (FormMessage (..))
-import Data.Monoid (mappend)
 import Data.Text (Text)
 
 dutchFormMessage :: FormMessage -> Text
-dutchFormMessage (MsgInvalidInteger t) = "Ongeldig aantal: " `Data.Monoid.mappend` t
+dutchFormMessage (MsgInvalidInteger t) = "Ongeldig aantal: " `mappend` t
 dutchFormMessage (MsgInvalidNumber t)  = "Ongeldig getal: " `mappend` t
 dutchFormMessage (MsgInvalidEntry t)   = "Ongeldige invoer: " `mappend` t
 dutchFormMessage MsgInvalidTimeFormat  = "Ongeldige tijd, het juiste formaat is (UU:MM[:SS])"
@@ -24,3 +24,5 @@
 dutchFormMessage MsgBoolYes            = "Ja"
 dutchFormMessage MsgBoolNo             = "Nee"
 dutchFormMessage MsgDelete             = "Verwijderen?"
+dutchFormMessage (MsgInvalidHexColorFormat t) = "Ongeldige kleur, moet de hexadecimale indeling #rrggbb hebben: " `mappend` t
+dutchFormMessage (MsgInvalidDatetimeFormat t) = "Ongeldige datum/tijd, moet de indeling JJJJ-MM-DD(T| )UU:MM[:SS] hebben: " `mappend` t
diff --git a/Yesod/Form/I18n/English.hs b/Yesod/Form/I18n/English.hs
--- a/Yesod/Form/I18n/English.hs
+++ b/Yesod/Form/I18n/English.hs
@@ -1,12 +1,12 @@
 {-# LANGUAGE OverloadedStrings #-}
+
 module Yesod.Form.I18n.English where
 
 import Yesod.Form.Types (FormMessage (..))
-import Data.Monoid (mappend)
 import Data.Text (Text)
 
 englishFormMessage :: FormMessage -> Text
-englishFormMessage (MsgInvalidInteger t) = "Invalid integer: " `Data.Monoid.mappend` t
+englishFormMessage (MsgInvalidInteger t) = "Invalid integer: " `mappend` t
 englishFormMessage (MsgInvalidNumber t) = "Invalid number: " `mappend` t
 englishFormMessage (MsgInvalidEntry t) = "Invalid entry: " `mappend` t
 englishFormMessage MsgInvalidTimeFormat = "Invalid time, must be in HH:MM[:SS] format"
@@ -24,3 +24,5 @@
 englishFormMessage MsgBoolYes = "Yes"
 englishFormMessage MsgBoolNo = "No"
 englishFormMessage MsgDelete = "Delete?"
+englishFormMessage (MsgInvalidHexColorFormat t) = "Invalid color, must be in #rrggbb hexadecimal format: " `mappend` t
+englishFormMessage (MsgInvalidDatetimeFormat t) = "Invalid datetime, must be in YYYY-MM-DD(T| )HH:MM[:SS] format: " `mappend` t
diff --git a/Yesod/Form/I18n/French.hs b/Yesod/Form/I18n/French.hs
--- a/Yesod/Form/I18n/French.hs
+++ b/Yesod/Form/I18n/French.hs
@@ -1,12 +1,12 @@
 {-# LANGUAGE OverloadedStrings #-}
+
 module Yesod.Form.I18n.French (frenchFormMessage) where
 
 import Yesod.Form.Types (FormMessage (..))
-import Data.Monoid (mappend)
 import Data.Text (Text)
 
 frenchFormMessage :: FormMessage -> Text
-frenchFormMessage (MsgInvalidInteger t) = "Entier invalide : " `Data.Monoid.mappend` t
+frenchFormMessage (MsgInvalidInteger t) = "Entier invalide : " `mappend` t
 frenchFormMessage (MsgInvalidNumber t) = "Nombre invalide : " `mappend` t
 frenchFormMessage (MsgInvalidEntry t) = "Entrée invalide : " `mappend` t
 frenchFormMessage MsgInvalidTimeFormat = "Heure invalide (elle doit être au format HH:MM ou HH:MM:SS"
@@ -24,3 +24,5 @@
 frenchFormMessage MsgBoolYes = "Oui"
 frenchFormMessage MsgBoolNo = "Non"
 frenchFormMessage MsgDelete = "Détruire ?"
+frenchFormMessage (MsgInvalidHexColorFormat t) = "Couleur non valide. doit être au format hexadécimal #rrggbb : " `mappend` t
+frenchFormMessage (MsgInvalidDatetimeFormat t) = "Date/heure non valide. doit être au format AAAA-MM-JJ(T| )HH:MM[:SS] : " `mappend` t
diff --git a/Yesod/Form/I18n/German.hs b/Yesod/Form/I18n/German.hs
--- a/Yesod/Form/I18n/German.hs
+++ b/Yesod/Form/I18n/German.hs
@@ -1,12 +1,12 @@
 {-# LANGUAGE OverloadedStrings #-}
+
 module Yesod.Form.I18n.German where
 
 import Yesod.Form.Types (FormMessage (..))
-import Data.Monoid (mappend)
 import Data.Text (Text)
 
 germanFormMessage :: FormMessage -> Text
-germanFormMessage (MsgInvalidInteger t) = "Ungültige Ganzzahl: " `Data.Monoid.mappend` t
+germanFormMessage (MsgInvalidInteger t) = "Ungültige Ganzzahl: " `mappend` t
 germanFormMessage (MsgInvalidNumber t) = "Ungültige Zahl: " `mappend` t
 germanFormMessage (MsgInvalidEntry t) = "Ungültiger Eintrag: " `mappend` t
 germanFormMessage MsgInvalidTimeFormat = "Ungültiges Zeitformat, HH:MM[:SS] Format erwartet"
@@ -24,3 +24,5 @@
 germanFormMessage MsgBoolYes = "Ja"
 germanFormMessage MsgBoolNo = "Nein"
 germanFormMessage MsgDelete = "Löschen?"
+germanFormMessage (MsgInvalidHexColorFormat t) = "Ungültige Farbe, muss im Hexadezimalformat #rrggbb vorliegen: " `mappend` t
+germanFormMessage (MsgInvalidDatetimeFormat t) = "Ungültige Datums- und Uhrzeitangabe, muss im Format YYYY-MM-DD(T| )HH:MM[:SS] vorliegen: " `mappend` t
diff --git a/Yesod/Form/I18n/Japanese.hs b/Yesod/Form/I18n/Japanese.hs
--- a/Yesod/Form/I18n/Japanese.hs
+++ b/Yesod/Form/I18n/Japanese.hs
@@ -1,12 +1,12 @@
 {-# LANGUAGE OverloadedStrings #-}
+
 module Yesod.Form.I18n.Japanese where
 
 import Yesod.Form.Types (FormMessage (..))
-import Data.Monoid (mappend)
 import Data.Text (Text)
 
 japaneseFormMessage :: FormMessage -> Text
-japaneseFormMessage (MsgInvalidInteger t) = "無効な整数です: " `Data.Monoid.mappend` t
+japaneseFormMessage (MsgInvalidInteger t) = "無効な整数です: " `mappend` t
 japaneseFormMessage (MsgInvalidNumber t) = "無効な数値です: " `mappend` t
 japaneseFormMessage (MsgInvalidEntry t) = "無効な入力です: " `mappend` t
 japaneseFormMessage MsgInvalidTimeFormat = "無効な時刻です。HH:MM[:SS]フォーマットで入力してください"
@@ -24,3 +24,5 @@
 japaneseFormMessage MsgBoolYes = "はい"
 japaneseFormMessage MsgBoolNo = "いいえ"
 japaneseFormMessage MsgDelete = "削除しますか?"
+japaneseFormMessage (MsgInvalidHexColorFormat t) = "無効な色。＃rrggbb16進形式である必要があります: " `mappend` t
+japaneseFormMessage (MsgInvalidDatetimeFormat t) = "無効な日時です。YYYY-MM-DD(T| )HH:MM[:SS] 形式である必要があります: " `mappend` t
diff --git a/Yesod/Form/I18n/Korean.hs b/Yesod/Form/I18n/Korean.hs
--- a/Yesod/Form/I18n/Korean.hs
+++ b/Yesod/Form/I18n/Korean.hs
@@ -1,12 +1,12 @@
 {-# LANGUAGE OverloadedStrings #-}
+
 module Yesod.Form.I18n.Korean where
 
 import Yesod.Form.Types (FormMessage (..))
-import Data.Monoid (mappend)
 import Data.Text (Text)
 
 koreanFormMessage :: FormMessage -> Text
-koreanFormMessage (MsgInvalidInteger t) = "잘못된 정수입니다: " `Data.Monoid.mappend` t
+koreanFormMessage (MsgInvalidInteger t) = "잘못된 정수입니다: " `mappend` t
 koreanFormMessage (MsgInvalidNumber t) = "잘못된 숫자입니다: " `mappend` t
 koreanFormMessage (MsgInvalidEntry t) = "잘못된 입력입니다: " `mappend` t
 koreanFormMessage MsgInvalidTimeFormat = "잘못된 시간입니다. HH:MM[:SS] 형태로 입력하세요"
@@ -24,3 +24,5 @@
 koreanFormMessage MsgBoolYes = "예"
 koreanFormMessage MsgBoolNo = "아니오"
 koreanFormMessage MsgDelete = "삭제하시겠습니까?"
+koreanFormMessage (MsgInvalidHexColorFormat t) = "색상이 잘못되었습니다. #rrggbb 16진수 형식이어야 합니다.: " `mappend` t
+koreanFormMessage (MsgInvalidDatetimeFormat t) = "날짜/시간이 잘못되었습니다. YYYY-MM-DD(T| )HH:MM[:SS] 형식이어야 합니다.: " `mappend` t
diff --git a/Yesod/Form/I18n/Norwegian.hs b/Yesod/Form/I18n/Norwegian.hs
--- a/Yesod/Form/I18n/Norwegian.hs
+++ b/Yesod/Form/I18n/Norwegian.hs
@@ -1,12 +1,12 @@
 {-# LANGUAGE OverloadedStrings #-}
+
 module Yesod.Form.I18n.Norwegian where
 
 import Yesod.Form.Types (FormMessage (..))
-import Data.Monoid (mappend)
 import Data.Text (Text)
 
 norwegianBokmålFormMessage :: FormMessage -> Text
-norwegianBokmålFormMessage (MsgInvalidInteger t) = "Ugyldig antall: " `Data.Monoid.mappend` t
+norwegianBokmålFormMessage (MsgInvalidInteger t) = "Ugyldig antall: " `mappend` t
 norwegianBokmålFormMessage (MsgInvalidNumber t) = "Ugyldig nummer: " `mappend` t
 norwegianBokmålFormMessage (MsgInvalidEntry t) = "Ugyldig oppføring: " `mappend` t
 norwegianBokmålFormMessage MsgInvalidTimeFormat = "Ugyldig klokkeslett, må være i formatet HH:MM[:SS]"
@@ -24,3 +24,5 @@
 norwegianBokmålFormMessage MsgBoolNo = "Nei"
 norwegianBokmålFormMessage MsgDelete = "Slette?"
 norwegianBokmålFormMessage MsgCsrfWarning = "Som beskyttelse mot «cross-site request forgery»-angrep, vennligst bekreft innsendt skjema."
+norwegianBokmålFormMessage (MsgInvalidHexColorFormat t) = "Ugyldig farge, må være i #rrggbb heksadesimalt format: " `mappend` t
+norwegianBokmålFormMessage (MsgInvalidDatetimeFormat t) = "Ugyldig datoklokkeslett, må være i formatet ÅÅÅÅ-MM-DD(T| )HH:MM[:SS]:" `mappend` t
diff --git a/Yesod/Form/I18n/Portuguese.hs b/Yesod/Form/I18n/Portuguese.hs
--- a/Yesod/Form/I18n/Portuguese.hs
+++ b/Yesod/Form/I18n/Portuguese.hs
@@ -1,12 +1,12 @@
 {-# LANGUAGE OverloadedStrings #-}
+
 module Yesod.Form.I18n.Portuguese where
 
 import Yesod.Form.Types (FormMessage (..))
-import Data.Monoid (mappend)
 import Data.Text (Text)
 
 portugueseFormMessage :: FormMessage -> Text
-portugueseFormMessage (MsgInvalidInteger t) = "Número inteiro inválido: " `Data.Monoid.mappend` t
+portugueseFormMessage (MsgInvalidInteger t) = "Número inteiro inválido: " `mappend` t
 portugueseFormMessage (MsgInvalidNumber t) = "Número inválido: " `mappend` t
 portugueseFormMessage (MsgInvalidEntry t) = "Entrada inválida: " `mappend` t
 portugueseFormMessage MsgInvalidTimeFormat = "Hora inválida, deve estar no formato HH:MM[:SS]"
@@ -24,3 +24,5 @@
 portugueseFormMessage MsgBoolYes = "Sim"
 portugueseFormMessage MsgBoolNo = "Não"
 portugueseFormMessage MsgDelete = "Remover?"
+portugueseFormMessage (MsgInvalidHexColorFormat t) = "Cor inválida, deve estar no formato #rrggbb hexadecimal: " `mappend` t
+portugueseFormMessage (MsgInvalidDatetimeFormat t) = "Data e hora inválida, deve estar no formato AAAA-MM-DD(T| )HH:MM[:SS]: " `mappend` t
diff --git a/Yesod/Form/I18n/Romanian.hs b/Yesod/Form/I18n/Romanian.hs
new file mode 100644
--- /dev/null
+++ b/Yesod/Form/I18n/Romanian.hs
@@ -0,0 +1,31 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Yesod.Form.I18n.Romanian where
+
+import Yesod.Form.Types (FormMessage (..))
+import Data.Text (Text)
+
+-- | Romanian translation
+--
+-- @since 1.7.5
+romanianFormMessage :: FormMessage -> Text
+romanianFormMessage (MsgInvalidInteger t) = "Număr întreg nevalid: " `mappend` t
+romanianFormMessage (MsgInvalidNumber t) = "Număr nevalid: " `mappend` t
+romanianFormMessage (MsgInvalidEntry t) = "Valoare nevalidă: " `mappend` t
+romanianFormMessage MsgInvalidTimeFormat = "Oră nevalidă. Formatul necesar este HH:MM[:SS]"
+romanianFormMessage MsgInvalidDay = "Dată nevalidă. Formatul necesar este AAAA-LL-ZZ"
+romanianFormMessage (MsgInvalidUrl t) = "Adresă URL nevalidă: " `mappend` t
+romanianFormMessage (MsgInvalidEmail t) = "Adresă de e-mail nevalidă: " `mappend` t
+romanianFormMessage (MsgInvalidHour t) = "Oră nevalidă: " `mappend` t
+romanianFormMessage (MsgInvalidMinute t) = "Minut nevalid: " `mappend` t
+romanianFormMessage (MsgInvalidSecond t) = "Secundă nevalidă: " `mappend` t
+romanianFormMessage MsgCsrfWarning = "Ca protecție împotriva atacurilor CSRF, vă rugăm să confirmați trimiterea formularului."
+romanianFormMessage MsgValueRequired = "Câmp obligatoriu"
+romanianFormMessage (MsgInputNotFound t) = "Valoare inexistentă: " `mappend` t
+romanianFormMessage MsgSelectNone = "<Niciuna>"
+romanianFormMessage (MsgInvalidBool t) = "Valoare booleană nevalidă: " `mappend` t
+romanianFormMessage MsgBoolYes = "Da"
+romanianFormMessage MsgBoolNo = "Nu"
+romanianFormMessage MsgDelete = "Șterge?"
+romanianFormMessage (MsgInvalidHexColorFormat t) = "Culoare nevalidă. Formatul necesar este #rrggbb în hexazecimal: " `mappend` t
+romanianFormMessage (MsgInvalidDatetimeFormat t) = "Data și ora nevalidă, trebuie să fie în format AAAA-LL-ZZ(T| )HH:MM[:SS]: " `mappend` t
diff --git a/Yesod/Form/I18n/Russian.hs b/Yesod/Form/I18n/Russian.hs
--- a/Yesod/Form/I18n/Russian.hs
+++ b/Yesod/Form/I18n/Russian.hs
@@ -1,12 +1,12 @@
 {-# LANGUAGE OverloadedStrings #-}
+
 module Yesod.Form.I18n.Russian where
 
 import Yesod.Form.Types (FormMessage (..))
-import Data.Monoid (mappend)
 import Data.Text (Text)
 
 russianFormMessage :: FormMessage -> Text
-russianFormMessage (MsgInvalidInteger t) = "Неверно записано целое число: " `Data.Monoid.mappend` t
+russianFormMessage (MsgInvalidInteger t) = "Неверно записано целое число: " `mappend` t
 russianFormMessage (MsgInvalidNumber t) = "Неверный формат числа: " `mappend` t
 russianFormMessage (MsgInvalidEntry t) = "Неверный выбор: " `mappend` t
 russianFormMessage MsgInvalidTimeFormat = "Неверно указано время, используйте формат ЧЧ:ММ[:СС]"
@@ -24,3 +24,5 @@
 russianFormMessage MsgBoolYes = "Да"
 russianFormMessage MsgBoolNo = "Нет"
 russianFormMessage MsgDelete = "Удалить?"
+russianFormMessage (MsgInvalidHexColorFormat t) = "Недопустимое значение цвета, должен быть в шестнадцатеричном формате #rrggbb: " `mappend` t
+russianFormMessage (MsgInvalidDatetimeFormat t) = "Недопустимое значение даты и времени. Должно быть в формате ГГГГ-ММ-ДД(T| )ЧЧ:ММ[:СС]: " `mappend` t
diff --git a/Yesod/Form/I18n/Spanish.hs b/Yesod/Form/I18n/Spanish.hs
--- a/Yesod/Form/I18n/Spanish.hs
+++ b/Yesod/Form/I18n/Spanish.hs
@@ -3,11 +3,10 @@
 module Yesod.Form.I18n.Spanish where
 
 import Yesod.Form.Types (FormMessage (..))
-import Data.Monoid (mappend)
 import Data.Text (Text)
 
 spanishFormMessage :: FormMessage -> Text
-spanishFormMessage (MsgInvalidInteger t) = "Número entero inválido: " `Data.Monoid.mappend` t
+spanishFormMessage (MsgInvalidInteger t) = "Número entero inválido: " `mappend` t
 spanishFormMessage (MsgInvalidNumber t) = "Número inválido: " `mappend` t
 spanishFormMessage (MsgInvalidEntry t) = "Entrada inválida: " `mappend` t
 spanishFormMessage MsgInvalidTimeFormat = "Hora inválida, debe tener el formato HH:MM[:SS]"
@@ -25,3 +24,5 @@
 spanishFormMessage MsgBoolYes = "Sí"
 spanishFormMessage MsgBoolNo = "No"
 spanishFormMessage MsgDelete = "¿Eliminar?"
+spanishFormMessage (MsgInvalidHexColorFormat t) = "Color no válido, debe estar en formato hexadecimal #rrggbb: " `mappend` t
+spanishFormMessage (MsgInvalidDatetimeFormat t) = "Fecha y hora no válida; debe estar en formato AAAA-MM-DD(T| )HH:MM[:SS]: " `mappend` t
diff --git a/Yesod/Form/I18n/Swedish.hs b/Yesod/Form/I18n/Swedish.hs
--- a/Yesod/Form/I18n/Swedish.hs
+++ b/Yesod/Form/I18n/Swedish.hs
@@ -1,12 +1,12 @@
 {-# LANGUAGE OverloadedStrings #-}
+
 module Yesod.Form.I18n.Swedish where
 
 import Yesod.Form.Types (FormMessage (..))
-import Data.Monoid (mappend)
 import Data.Text (Text)
 
 swedishFormMessage :: FormMessage -> Text
-swedishFormMessage (MsgInvalidInteger t) = "Ogiltigt antal: " `Data.Monoid.mappend` t
+swedishFormMessage (MsgInvalidInteger t) = "Ogiltigt antal: " `mappend` t
 swedishFormMessage (MsgInvalidNumber t) = "Ogiltigt nummer: " `mappend` t
 swedishFormMessage (MsgInvalidEntry t) = "Invalid entry: " `mappend` t
 swedishFormMessage MsgInvalidTimeFormat = "Ogiltigt klockslag, måste vara på formatet HH:MM[:SS]"
@@ -24,3 +24,5 @@
 swedishFormMessage MsgBoolNo = "Nej"
 swedishFormMessage MsgDelete = "Radera?"
 swedishFormMessage MsgCsrfWarning = "Som skydd mot \"cross-site request forgery\" attacker, vänligen bekräfta skickandet av formuläret."
+swedishFormMessage (MsgInvalidHexColorFormat t) = "Ogiltig färg, måste vara i #rrggbb hexadecimalt format: " `mappend` t
+swedishFormMessage (MsgInvalidDatetimeFormat t) = "Ogiltig datumtid, måste vara i formatet ÅÅÅÅ-MM-DD(T| )TT:MM[:SS]: " `mappend` t
diff --git a/Yesod/Form/Input.hs b/Yesod/Form/Input.hs
--- a/Yesod/Form/Input.hs
+++ b/Yesod/Form/Input.hs
@@ -1,5 +1,6 @@
-{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE OverloadedStrings #-}
+
 -- | Provides for getting input from either GET or POST params without
 -- generating HTML forms. For more information, see:
 -- <http://www.yesodweb.com/book/forms#forms_kinds_of_forms>.
@@ -15,7 +16,6 @@
 
 import Yesod.Form.Types
 import Data.Text (Text)
-import Control.Applicative (Applicative (..))
 import Yesod.Core
 import Control.Monad (liftM, (<=<))
 import qualified Data.Map as Map
@@ -29,7 +29,7 @@
 newtype FormInput m a = FormInput { unFormInput :: HandlerSite m -> [Text] -> Env -> FileEnv -> m (Either DText a) }
 instance Monad m => Functor (FormInput m) where
     fmap a (FormInput f) = FormInput $ \c d e e' -> liftM (either Left (Right . a)) $ f c d e e'
-instance Monad m => Control.Applicative.Applicative (FormInput m) where
+instance Monad m => Applicative (FormInput m) where
     pure = FormInput . const . const . const . const . return . Right
     (FormInput f) <*> (FormInput x) = FormInput $ \c d e e' -> do
         res1 <- f c d e e'
diff --git a/Yesod/Form/Jquery.hs b/Yesod/Form/Jquery.hs
--- a/Yesod/Form/Jquery.hs
+++ b/Yesod/Form/Jquery.hs
@@ -1,7 +1,9 @@
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+
 -- | Some fields spiced up with jQuery UI.
 module Yesod.Form.Jquery
     ( YesodJquery (..)
@@ -20,11 +22,10 @@
 import Data.Default
 import Text.Julius (rawJS)
 import Data.Text (Text, pack, unpack)
-import Data.Monoid (mconcat)
 
 -- | Gets the Google hosted jQuery UI 1.8 CSS file with the given theme.
 googleHostedJqueryUiCss :: Text -> Text
-googleHostedJqueryUiCss theme = Data.Monoid.mconcat
+googleHostedJqueryUiCss theme = mconcat
     [ "//ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/"
     , theme
     , "/jquery-ui.css"
@@ -53,16 +54,16 @@
     urlJqueryUiDateTimePicker :: a -> Either (Route a) Text
     urlJqueryUiDateTimePicker _ = Right "http://github.com/gregwebs/jquery.ui.datetimepicker/raw/master/jquery.ui.datetimepicker.js"
 
-jqueryDayField :: (RenderMessage site FormMessage, YesodJquery site) => JqueryDaySettings -> Field (HandlerT site IO) Day
+jqueryDayField :: (RenderMessage site FormMessage, YesodJquery site) => JqueryDaySettings -> Field (HandlerFor site) Day
 jqueryDayField = flip jqueryDayField' "date"
 
 -- | Use jQuery's datepicker as the underlying implementation.
 --
 -- Since 1.4.3
-jqueryDatePickerDayField :: (RenderMessage site FormMessage, YesodJquery site) => JqueryDaySettings -> Field (HandlerT site IO) Day
+jqueryDatePickerDayField :: (RenderMessage site FormMessage, YesodJquery site) => JqueryDaySettings -> Field (HandlerFor site) Day
 jqueryDatePickerDayField = flip jqueryDayField' "text"
 
-jqueryDayField' :: (RenderMessage site FormMessage, YesodJquery site) => JqueryDaySettings -> Text -> Field (HandlerT site IO) Day
+jqueryDayField' :: (RenderMessage site FormMessage, YesodJquery site) => JqueryDaySettings -> Text -> Field (HandlerFor site) Day
 jqueryDayField' jds inputType = Field
     { fieldParse = parseHelper $ maybe
                   (Left MsgInvalidDay)
@@ -107,13 +108,13 @@
         ]
 
 jqueryAutocompleteField :: (RenderMessage site FormMessage, YesodJquery site)
-                        => Route site -> Field (HandlerT site IO) Text
+                        => Route site -> Field (HandlerFor site) Text
 jqueryAutocompleteField = jqueryAutocompleteField' 2
 
 jqueryAutocompleteField' :: (RenderMessage site FormMessage, YesodJquery site)
                          => Int -- ^ autocomplete minimum length
                          -> Route site
-                         -> Field (HandlerT site IO) Text
+                         -> Field (HandlerFor site) Text
 jqueryAutocompleteField' minLen src = Field
     { fieldParse = parseHelper $ Right
     , fieldView = \theId name attrs val isReq -> do
diff --git a/Yesod/Form/MassInput.hs b/Yesod/Form/MassInput.hs
--- a/Yesod/Form/MassInput.hs
+++ b/Yesod/Form/MassInput.hs
@@ -1,8 +1,9 @@
-{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
 {-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE CPP#-}
+{-# LANGUAGE TypeOperators #-}
+
 -- | A module providing a means of creating multiple input forms, such as a
 -- list of 0 or more recipients.
 module Yesod.Form.MassInput
@@ -44,17 +45,17 @@
 
 -- | Generate a form that accepts 0 or more values from the user, allowing the
 -- user to specify that a new row is necessary.
-inputList :: (xml ~ WidgetT site IO (), RenderMessage site FormMessage)
+inputList :: (xml ~ WidgetFor site (), RenderMessage site FormMessage)
           => Html
           -- ^ label for the form
           -> ([[FieldView site]] -> xml)
           -- ^ how to display the rows, usually either 'massDivs' or 'massTable'
-          -> (Maybe a -> AForm (HandlerT site IO) a)
+          -> (Maybe a -> AForm (HandlerFor site) a)
           -- ^ display a single row of the form, where @Maybe a@ gives the
           -- previously submitted value
           -> Maybe [a]
           -- ^ default initial values for the form
-          -> AForm (HandlerT site IO) [a]
+          -> AForm (HandlerFor site) [a]
 inputList label fixXml single mdef = formToAForm $ do
     theId <- lift newIdent
     down 1
@@ -94,9 +95,9 @@
         , fvRequired = False
         }])
 
-withDelete :: (xml ~ WidgetT site IO (), RenderMessage site FormMessage)
-           => AForm (HandlerT site IO) a
-           -> MForm (HandlerT site IO) (Either xml (FormResult a, [FieldView site]))
+withDelete :: (xml ~ WidgetFor site (), RenderMessage site FormMessage)
+           => AForm (HandlerFor site) a
+           -> MForm (HandlerFor site) (Either xml (FormResult a, [FieldView site]))
 withDelete af = do
     down 1
     deleteName <- newFormIdent
@@ -129,7 +130,7 @@
 
 massDivs, massTable
          :: [[FieldView site]]
-         -> WidgetT site IO ()
+         -> WidgetFor site ()
 massDivs viewss = [whamlet|
 $newline never
 $forall views <- viewss
diff --git a/Yesod/Form/Nic.hs b/Yesod/Form/Nic.hs
--- a/Yesod/Form/Nic.hs
+++ b/Yesod/Form/Nic.hs
@@ -1,8 +1,9 @@
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE CPP #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+
 -- | Provide the user with a rich text editor.
 --
 -- According to NIC editor homepage it is not actively maintained since June
@@ -29,7 +30,7 @@
     urlNicEdit :: a -> Either (Route a) Text
     urlNicEdit _ = Right "http://js.nicedit.com/nicEdit-latest.js"
 
-nicHtmlField :: YesodNic site => Field (HandlerT site IO) Html
+nicHtmlField :: YesodNic site => Field (HandlerFor site) Html
 nicHtmlField = Field
     { fieldParse = \e _ -> return . Right . fmap (preEscapedToMarkup . sanitizeBalance) . listToMaybe $ e
     , fieldView = \theId name attrs val _isReq -> do
diff --git a/Yesod/Form/Option.hs b/Yesod/Form/Option.hs
new file mode 100644
--- /dev/null
+++ b/Yesod/Form/Option.hs
@@ -0,0 +1,96 @@
+{-# LANGUAGE FlexibleContexts #-}
+
+module Yesod.Form.Option where
+
+import Yesod.Core
+import Yesod.Form.Fields
+
+-- | Creates an `OptionList` from a `List`, using the `PathPiece` instance for
+-- the external value and a custom function for the user-facing value.
+--
+-- @since 1.7.7
+--
+-- PathPiece instances should provide suitable external values, since path
+-- pieces serve to be exposed through URLs or HTML anyway. Show/Read instances
+-- are avoided here since they could leak internal representations to forms,
+-- query params, javascript etc.
+--
+-- === __Example usage__
+--
+-- > data UserRole = URSalesTeam | URSalesHead | URTechTeam | URTechHead
+-- >
+-- > instance PathPiece UserDepartment where
+-- >   toPathPiece = \case
+-- >     URSalesTeam -> "sales-team"
+-- >     URSalesHead -> "sales-head"
+-- >     URTechTeam -> "tech-team"
+-- >     URTechHead -> "tech-head"
+-- >   fromPathPiece = \case
+-- >     "sales-team" -> Just URSalesTeam
+-- >     "sales-head" -> Just URSalesHead
+-- >     "tech-team" -> Just URTechTeam
+-- >     "tech-head" -> Just URTechHead
+-- >     _ -> Nothing
+-- >
+-- > userRoleOptions ::
+-- >   (MonadHandler m, RenderMessage (HandlerSite m) msg) => m (OptionList UserRole)
+-- > userRoleOptions = optionsFromList' userRoles toMsg
+-- >   where
+-- >   userRoles = [URSalesTeam, URSalesHead, URTechTeam, URTechHead]
+-- >   toMsg :: UserRole -> Text
+-- >   toMsg = \case
+-- >     URSalesTeam -> "Sales Team"
+-- >     URSalesHead -> "Head of Sales Team"
+-- >     URTechTeam -> "Tech Team"
+-- >     URTechHead -> "Head of Tech Team"
+--
+-- userRoleOptions, will produce an OptionList with the following attributes:
+--
+-- > +----------------+----------------+--------------------+
+-- > | Internal Value | External Value | User-facing Value  |
+-- > +----------------+----------------+--------------------+
+-- > | URSalesTeam    | sales-team     | Sales Team         |
+-- > +----------------+----------------+--------------------+
+-- > | URSalesHead    | sales-head     | Head of Sales Team |
+-- > +----------------+----------------+--------------------+
+-- > | URTechTeam     | tech-team      | Tech Team          |
+-- > +----------------+----------------+--------------------+
+-- > | URTechHead     | tech-head      | Head of Tech Team  |
+-- > +----------------+----------------+--------------------+
+--
+-- Note that the type constraint allows localizable messages in place of toMsg (see
+-- https://en.wikipedia.org/wiki/Yesod_(web_framework)#Localizable_messages).
+
+optionsFromList' ::
+     MonadHandler m
+  => RenderMessage (HandlerSite m) msg
+  => PathPiece a
+  => [a]
+  -> (a -> msg)
+  -> m (OptionList a)
+optionsFromList' lst toDisplay = do
+  mr <- getMessageRender
+  pure $ mkOptionList $ flip map lst $ \v -> Option
+    { optionDisplay = mr $ toDisplay v
+    , optionInternalValue = v
+    , optionExternalValue = toPathPiece v
+    }
+
+-- | Creates an `OptionList` from an `Enum`.
+--
+-- @since 1.7.7
+--
+-- optionsEnum' == optionsFromList' [minBound..maxBound]
+--
+-- Creates an `OptionList` containing every constructor of `a`, so that these
+-- constructors do not need to be typed out. Bounded and Enum instances must
+-- exist for `a` to use this.
+optionsEnum' ::
+     MonadHandler m
+  => RenderMessage (HandlerSite m) msg
+  => PathPiece a
+  => Enum a
+  => Bounded a
+  => (a -> msg)
+  -> m (OptionList a)
+optionsEnum' = optionsFromList' [minBound..maxBound]
diff --git a/Yesod/Form/Types.hs b/Yesod/Form/Types.hs
--- a/Yesod/Form/Types.hs
+++ b/Yesod/Form/Types.hs
@@ -1,8 +1,9 @@
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE CPP #-}
+{-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TypeFamilies #-}
+
 module Yesod.Form.Types
     ( -- * Helpers
       Enctype (..)
@@ -25,18 +26,16 @@
 import Control.Monad.Trans.RWS (RWST)
 import Control.Monad.Trans.Writer (WriterT)
 import Data.Text (Text)
-import Data.Monoid (Monoid (..))
 import Text.Blaze (Markup, ToMarkup (toMarkup), ToValue (toValue))
 #define Html Markup
 #define ToHtml ToMarkup
 #define toHtml toMarkup
-import Control.Applicative ((<$>), Alternative (..), Applicative (..))
+import Control.Applicative (Alternative (..))
 import Control.Monad (liftM)
 import Control.Monad.Trans.Class
 import Data.String (IsString (..))
 import Yesod.Core
 import qualified Data.Map as Map
-import Data.Semigroup (Semigroup, (<>))
 import Data.Traversable
 import Data.Foldable
 
@@ -50,23 +49,23 @@
 data FormResult a = FormMissing
                   | FormFailure [Text]
                   | FormSuccess a
-    deriving Show
+    deriving (Show, Eq)
 instance Functor FormResult where
     fmap _ FormMissing = FormMissing
     fmap _ (FormFailure errs) = FormFailure errs
     fmap f (FormSuccess a) = FormSuccess $ f a
-instance Control.Applicative.Applicative FormResult where
+instance Applicative FormResult where
     pure = FormSuccess
     (FormSuccess f) <*> (FormSuccess g) = FormSuccess $ f g
     (FormFailure x) <*> (FormFailure y) = FormFailure $ x ++ y
     (FormFailure x) <*> _ = FormFailure x
     _ <*> (FormFailure y) = FormFailure y
     _ <*> _ = FormMissing
-instance Data.Monoid.Monoid m => Monoid (FormResult m) where
+instance Monoid m => Monoid (FormResult m) where
     mempty = pure mempty
-    mappend x y = mappend <$> x <*> y
+    mappend = (<>)
 instance Semigroup m => Semigroup (FormResult m) where
-    x <> y = (<>) Control.Applicative.<$> x <*> y
+    x <> y = (<>) <$> x <*> y
 
 -- | @since 1.4.5
 instance Data.Foldable.Foldable FormResult where
@@ -104,9 +103,9 @@
     toValue Multipart = "multipart/form-data"
 instance Monoid Enctype where
     mempty = UrlEncoded
-    mappend UrlEncoded UrlEncoded = UrlEncoded
-    mappend _ _ = Multipart
-instance Semigroup Enctype
+instance Semigroup Enctype where
+    UrlEncoded <> UrlEncoded = UrlEncoded
+    _          <> _          = Multipart
 
 data Ints = IntCons Int Ints | IntSingle Int
 instance Show Ints where
@@ -163,9 +162,21 @@
         (a, b, ints', c) <- f mr env ints
         (x, y, ints'', z) <- g mr env ints'
         return (a <*> x, b . y, ints'', c `mappend` z)
+
+#if MIN_VERSION_transformers(0,6,0)
+instance Monad m => Monad (AForm m) where
+    (AForm f) >>= k = AForm $ \mr env ints -> do
+        (a, b, ints', c) <- f mr env ints
+        case a of
+          FormSuccess r -> do
+            (x, y, ints'', z) <- unAForm (k r) mr env ints'
+            return (x, b . y, ints'', c `mappend` z)
+          FormFailure err -> pure (FormFailure err, b, ints', c)
+          FormMissing -> pure (FormMissing, b, ints', c)
+#endif
 instance (Monad m, Monoid a) => Monoid (AForm m a) where
     mempty = pure mempty
-    mappend a b = mappend <$> a <*> b
+    mappend = (<>)
 instance (Monad m, Semigroup a) => Semigroup (AForm m a) where
     a <> b = (<>) <$> a <*> b
 
@@ -189,7 +200,7 @@
     { fvLabel :: Html
     , fvTooltip :: Maybe Html
     , fvId :: Text
-    , fvInput :: WidgetT site IO ()
+    , fvInput :: WidgetFor site ()
     , fvErrors :: Maybe Html
     , fvRequired :: Bool
     }
@@ -200,7 +211,7 @@
    -> [(Text, Text)] -- ^ Attributes
    -> Either Text a -- ^ Either (invalid text) or (legitimate result)
    -> Bool -- ^ Required?
-   -> WidgetT (HandlerSite m) IO ()
+   -> WidgetFor (HandlerSite m) ()
 
 data Field m a = Field
     { fieldParse :: [Text] -> [FileInfo] -> m (Either (SomeMessage (HandlerSite m)) (Maybe a))
@@ -226,4 +237,6 @@
                  | MsgBoolYes
                  | MsgBoolNo
                  | MsgDelete
+                 | MsgInvalidHexColorFormat Text
+                 | MsgInvalidDatetimeFormat Text
     deriving (Show, Eq, Read)
diff --git a/yesod-form.cabal b/yesod-form.cabal
--- a/yesod-form.cabal
+++ b/yesod-form.cabal
@@ -1,5 +1,6 @@
+cabal-version:   >= 1.10
 name:            yesod-form
-version:         1.4.16
+version:         1.7.9.3
 license:         MIT
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
@@ -7,10 +8,9 @@
 synopsis:        Form handling support for Yesod Web Framework
 category:        Web, Yesod
 stability:       Stable
-cabal-version:   >= 1.8
 build-type:      Simple
 homepage:        http://www.yesodweb.com/
-description:     API docs and the README are available at <http://www.stackage.org/package/yesod-form>.  Third-party packages which you can find useful: <http://hackage.haskell.org/package/yesod-form-richtext yesod-form-richtext> - richtext form fields (currntly it provides only Summernote support).
+description:     API docs and the README are available at <http://www.stackage.org/package/yesod-form>.  Third-party packages which you can find useful: <http://hackage.haskell.org/package/yesod-form-richtext yesod-form-richtext> - richtext form fields (currently it provides only Summernote support).
 extra-source-files: ChangeLog.md
                     README.md
 
@@ -19,36 +19,34 @@
   default: True
 
 library
-    build-depends:   base                  >= 4        && < 5
-                   , yesod-core            >= 1.4.14   && < 1.5
-                   , yesod-persistent      >= 1.4      && < 1.5
-                   , time                  >= 1.1.4
-                   , shakespeare           >= 2.0
-                   , persistent
-                   , template-haskell
-                   , transformers          >= 0.2.2
-                   , data-default
-                   , xss-sanitize          >= 0.3.0.1
+    default-language: Haskell2010
+    build-depends:   base                  >= 4.11     && < 5
+                   , aeson
+                   , attoparsec            >= 0.10
                    , blaze-builder         >= 0.2.1.4
-                   , email-validate        >= 1.0
-                   , bytestring            >= 0.9.1.4
-                   , text                  >= 0.9
-                   , wai                   >= 1.3
-                   , containers            >= 0.2
                    , blaze-html            >= 0.5
                    , blaze-markup          >= 0.5.1
-                   , attoparsec            >= 0.10
                    , byteable
-                   , aeson
+                   , bytestring            >= 0.9.1.4
+                   , containers            >= 0.2
+                   , data-default
+                   , email-validate        >= 1.0
+                   , persistent
                    , resourcet
-                   , semigroups
+                   , shakespeare           >= 2.0
+                   , text                  >= 0.9
+                   , time                  >= 1.1.4
+                   , transformers          >= 0.2.2
+                   , wai                   >= 1.3
+                   , xss-sanitize          >= 0.3.0.1
+                   , yesod-core            >= 1.6      && < 1.8
+                   , yesod-persistent      >= 1.6      && < 1.7
 
     if flag(network-uri)
       build-depends: network-uri >= 2.6
-    else
-      build-depends: network < 2.6
 
     exposed-modules: Yesod.Form
+                     Yesod.Form.Option
                      Yesod.Form.Types
                      Yesod.Form.Functions
                      Yesod.Form.Bootstrap3
@@ -70,10 +68,12 @@
                      Yesod.Form.I18n.Spanish
                      Yesod.Form.I18n.Chinese
                      Yesod.Form.I18n.Korean
+                     Yesod.Form.I18n.Romanian
                      -- FIXME Yesod.Helpers.Crud
     ghc-options:     -Wall
 
 test-suite test
+    default-language: Haskell2010
     type: exitcode-stdio-1.0
     main-is: main.hs
     hs-source-dirs: test
