diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,4 @@
+## 1.4.2
+
+Added `timeFieldTypeTime` and `timeFieldTypeText`, and deprecated `timeField`
+itself.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,4 @@
+## yesod-form
+
+Form handling for Yesod, in the same style as formlets. See [the forms
+chapter](http://www.yesodweb.com/book/forms) of the Yesod book.
diff --git a/Yesod/Form/Fields.hs b/Yesod/Form/Fields.hs
--- a/Yesod/Form/Fields.hs
+++ b/Yesod/Form/Fields.hs
@@ -4,6 +4,11 @@
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE CPP #-}
+-- | 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".
+--
+-- See the Yesod book <http://www.yesodweb.com/book/forms chapter on forms> for a broader overview of forms in Yesod.
 module Yesod.Form.Fields
     ( -- * i18n
       FormMessage (..)
@@ -16,6 +21,8 @@
     , intField
     , dayField
     , timeField
+    , timeFieldTypeTime
+    , timeFieldTypeText
     , htmlField
     , emailField
     , multiEmailField
@@ -99,7 +106,7 @@
 defaultFormMessage :: FormMessage -> Text
 defaultFormMessage = englishFormMessage
 
-
+-- | Creates a input with @type="number"@ and @step=1@.
 intField :: (Monad m, Integral i, RenderMessage (HandlerSite m) FormMessage) => Field m i
 intField = Field
     { fieldParse = parseHelper $ \s ->
@@ -117,6 +124,7 @@
     showVal = either id (pack . showI)
     showI x = show (fromIntegral x :: Integer)
 
+-- | Creates a input with @type="number"@ and @step=any@.
 doubleField :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m Double
 doubleField = Field
     { fieldParse = parseHelper $ \s ->
@@ -132,6 +140,9 @@
     }
   where showVal = either id (pack . show)
 
+-- | Creates an input with @type="date"@, validating the input using the 'parseDate' function.
+--
+-- Add the @time@ package and import the "Data.Time.Calendar" module to use this function.
 dayField :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m Day
 dayField = Field
     { fieldParse = parseHelper $ parseDate . unpack
@@ -143,12 +154,33 @@
     }
   where showVal = either id (pack . show)
 
+-- | An alias for 'timeFieldTypeText'.
 timeField :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m TimeOfDay
-timeField = Field
+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." #-}
+
+-- | 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  
+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).
+-- 
+-- Add the @time@ package and import the "Data.Time.LocalTime" module to use this function.
+--
+-- Since 1.4.2
+timeFieldTypeText :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m TimeOfDay
+timeFieldTypeText = timeFieldOfType "text"
+
+timeFieldOfType :: Monad m => RenderMessage (HandlerSite m) FormMessage => Text -> Field m TimeOfDay
+timeFieldOfType inputType = Field
     { fieldParse = parseHelper parseTime
     , fieldView = \theId name attrs val isReq -> toWidget [hamlet|
 $newline never
-<input id="#{theId}" name="#{name}" *{attrs} :isReq:required="" value="#{showVal val}">
+<input id="#{theId}" name="#{name}" *{attrs} type="#{inputType}" :isReq:required="" value="#{showVal val}">
 |]
     , fieldEnctype = UrlEncoded
     }
@@ -159,6 +191,7 @@
       where
         fullSec = fromInteger $ floor $ todSec tod
 
+-- | Creates a @\<textarea>@ tag whose input is sanitized to prevent XSS attacks and is validated for having balanced tags.
 htmlField :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m Html
 htmlField = Field
     { fieldParse = parseHelper $ Right . preEscapedText . sanitizeBalance
@@ -170,8 +203,11 @@
     }
   where showVal = either id (pack . renderHtml)
 
--- | A newtype wrapper around a 'Text' that converts newlines to HTML
--- br-tags.
+-- | 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)
 instance PersistFieldSql Textarea where
@@ -190,6 +226,7 @@
         writeHtmlEscapedChar '\n' = writeByteString "<br>"
         writeHtmlEscapedChar c    = B.writeHtmlEscapedChar c
 
+-- | Creates a @\<textarea>@ tag whose returned value is wrapped in a 'Textarea'; see 'Textarea' for details.
 textareaField :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m Textarea
 textareaField = Field
     { fieldParse = parseHelper $ Right . Textarea
@@ -200,6 +237,7 @@
     , fieldEnctype = UrlEncoded
     }
 
+-- | Creates an input with @type="hidden"@; you can use this to store information in a form that users shouldn't see (for example, Yesod stores CSRF tokens in a hidden field).
 hiddenField :: (Monad m, PathPiece p, RenderMessage (HandlerSite m) FormMessage)
             => Field m p
 hiddenField = Field
@@ -211,6 +249,7 @@
     , fieldEnctype = UrlEncoded
     }
 
+-- | Creates a input with @type="text"@.
 textField :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m Text
 textField = Field
     { fieldParse = parseHelper $ Right
@@ -221,7 +260,7 @@
 |]
     , fieldEnctype = UrlEncoded
     }
-
+-- | Creates an input with @type="password"@.
 passwordField :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m Text
 passwordField = Field
     { fieldParse = parseHelper $ Right
@@ -237,6 +276,7 @@
                 (x, _):_ -> Just x
                 [] -> Nothing
 
+-- | Parses a 'Day' from a 'String'.
 parseDate :: String -> Either FormMessage Day
 parseDate = maybe (Left MsgInvalidDay) Right
               . readMay . replace '/' '-'
@@ -292,7 +332,8 @@
         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
     { fieldParse = parseHelper $
@@ -307,7 +348,7 @@
     , fieldEnctype = UrlEncoded
     }
 
--- |
+-- | Creates an input with @type="email"@ with the <http://www.w3.org/html/wg/drafts/html/master/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
 multiEmailField :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m [Text]
@@ -333,6 +374,7 @@
         emailToText = decodeUtf8With lenientDecode . Email.toByteString
 
 type AutoFocus = Bool
+-- | Creates an input with @type="search"@. For <http://caniuse.com/#search=autofocus browsers without autofocus support>, a JS fallback is used if @AutoFocus@ is true.
 searchField :: Monad m => RenderMessage (HandlerSite m) FormMessage => AutoFocus -> Field m Text
 searchField autoFocus = Field
     { fieldParse = parseHelper Right
@@ -353,7 +395,7 @@
             |]
     , fieldEnctype = UrlEncoded
     }
-
+-- | Creates an input with @type="url"@, validating the URL according to RFC3986.
 urlField :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m Text
 urlField = Field
     { fieldParse = parseHelper $ \s ->
@@ -467,6 +509,13 @@
         \#{text}
 |])
 
+-- | 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". 
+--
+-- (Exact label titles will depend on localization).
 boolField :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m Bool
 boolField = Field
       { fieldParse = \e _ -> return $ boolParser e
@@ -498,10 +547,11 @@
       t -> Left $ SomeMessage $ MsgInvalidBool t
     showVal = either (\_ -> False)
 
--- | 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
---   response as Just False.
+-- | 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
+--   response as @Just False@.
 --
 --   Note that this makes the field always optional.
 --
@@ -635,6 +685,7 @@
                     Nothing -> Left $ SomeMessage $ MsgInvalidEntry x
                     Just y -> Right $ Just y
 
+-- | Creates an input with @type="file"@.
 fileField :: (Monad m, RenderMessage (HandlerSite m) FormMessage)
           => Field m FileInfo
 fileField = Field
diff --git a/Yesod/Form/Functions.hs b/Yesod/Form/Functions.hs
--- a/Yesod/Form/Functions.hs
+++ b/Yesod/Form/Functions.hs
@@ -254,8 +254,8 @@
             return $ Just (p', Map.unionsWith (++) $ map (\(k, v) -> Map.singleton k [v]) f)
 
 runFormPostNoToken :: MonadHandler m
-                   => (Html -> MForm m (FormResult a, xml))
-                   -> m ((FormResult a, xml), Enctype)
+                   => (Html -> MForm m a)
+                   -> m (a, Enctype)
 runFormPostNoToken form = do
     langs <- languages
     m <- getYesod
diff --git a/Yesod/Form/I18n/Dutch.hs b/Yesod/Form/I18n/Dutch.hs
new file mode 100644
--- /dev/null
+++ b/Yesod/Form/I18n/Dutch.hs
@@ -0,0 +1,26 @@
+{-# 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: " `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])"
+dutchFormMessage MsgInvalidDay         = "Ongeldige datum, het juiste formaat is (JJJJ-MM-DD)"
+dutchFormMessage (MsgInvalidUrl t)     = "Ongeldige URL: " `mappend` t
+dutchFormMessage (MsgInvalidEmail t)   = "Ongeldig e-mail adres: " `mappend` t
+dutchFormMessage (MsgInvalidHour t)    = "Ongeldig uur: " `mappend` t
+dutchFormMessage (MsgInvalidMinute t)  = "Ongeldige minuut: " `mappend` t
+dutchFormMessage (MsgInvalidSecond t)  = "Ongeldige seconde: " `mappend` t
+dutchFormMessage MsgCsrfWarning        = "Bevestig het indienen van het formulier, dit als veiligheidsmaatregel tegen \"cross-site request forgery\" aanvallen."
+dutchFormMessage MsgValueRequired      = "Verplicht veld"
+dutchFormMessage (MsgInputNotFound t)  = "Geen invoer gevonden: " `mappend` t
+dutchFormMessage MsgSelectNone         = "<Geen>"
+dutchFormMessage (MsgInvalidBool t)    = "Ongeldige waarheidswaarde: " `mappend` t
+dutchFormMessage MsgBoolYes            = "Ja"
+dutchFormMessage MsgBoolNo             = "Nee"
+dutchFormMessage MsgDelete             = "Verwijderen?"
diff --git a/yesod-form.cabal b/yesod-form.cabal
--- a/yesod-form.cabal
+++ b/yesod-form.cabal
@@ -1,5 +1,5 @@
 name:            yesod-form
-version:         1.4.1.1
+version:         1.4.2
 license:         MIT
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
@@ -11,6 +11,8 @@
 build-type:      Simple
 homepage:        http://www.yesodweb.com/
 description:     Form handling support for Yesod Web Framework
+extra-source-files: ChangeLog.md
+                    README.md
 
 flag network-uri
   description: Get Network.URI from the network-uri package
@@ -63,6 +65,7 @@
                      Yesod.Form.I18n.Japanese
                      Yesod.Form.I18n.Czech
                      Yesod.Form.I18n.Russian
+                     Yesod.Form.I18n.Dutch
                      -- FIXME Yesod.Helpers.Crud
     ghc-options:     -Wall
 
