diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,19 @@
+# Changelog for yesod-form-bulma
+
+## Unreleased changes
+
+- Upgrade to yesod-core 1.6
+- Add bulmaTextField
+- Add bulmaTextareaField
+- Add bulmaEmailField
+- Add bulmaCheckBoxField
+- Add bulmaSelectField
+- Add bulmaSelectFieldList
+- Add bulmaRadioField
+- Add bulmaRadioFieldList
+- Add bulmaIntField
+- Add bulmaCheckboxesFieldList
+- Add bulmaCheckboxesField
+- Add bulmaMultiSelectFieldList
+- Add bulmaMultiSelectField
+- Add Showcases
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Shinya Yamaguchi (c) 2018
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Shinya Yamaguchi nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,64 @@
+[![CircleCI](https://circleci.com/gh/waddlaw/yesod-form-bulma/tree/master.svg?style=svg)](https://circleci.com/gh/waddlaw/yesod-form-bulma/tree/master)
+
+# yesod-form-bulma
+
+- [Bulma](https://bulma.io/documentation/form/)
+- [Bulma-Extensions](https://wikiki.github.io/form/checkradio/)
+
+
+## Screenshot
+
+![a](https://i.imgur.com/SZnv42b.png)
+
+## Run
+
+simple example.
+
+```sh
+$ stack build
+$ stack exec example
+```
+
+full components showcase.
+
+```sh
+$ stack build
+$ stack exec showcase
+```
+
+Access to [localhost:3100](http://localhost:3100)
+
+## Implemented status
+
+### Yesod.Form.Fields
+
+#### Fields
+
+- [x] bulmaTextField
+- [ ] bulmaPasswordField
+- [x] bulmaTextareaField
+- [ ] bulmaHiddenField
+- [x] bulmaIntField
+- [ ] bulmaDayField
+- [ ] bulmaTimeFieldTypeTime
+- [ ] bulmaTimeFieldTypeText
+- [ ] bulmaHtmlField
+- [x] bulmaEmailField
+- [ ] bulmaMultiEmailField
+- [ ] bulmaSearchField
+- [ ] bulmaUrlField
+- [ ] bulmaDoubleField
+- [ ] bulmaBoolField
+- [x] bulmaCheckBoxField
+- [ ] bulmaFileField
+
+#### Options
+
+- [x] bulmaSelectField
+- [x] bulmaSelectFieldList
+- [x] bulmaRadioField
+- [x] bulmaRadioFieldList
+- [x] bulmaCheckboxesField
+- [x] bulmaCheckboxesFieldList
+- [x] bulmaMultiSelectField
+- [x] bulmaMultiSelectFieldList
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/app/Example/Main.hs b/app/Example/Main.hs
new file mode 100644
--- /dev/null
+++ b/app/Example/Main.hs
@@ -0,0 +1,81 @@
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings     #-}
+{-# LANGUAGE QuasiQuotes           #-}
+{-# LANGUAGE TemplateHaskell       #-}
+{-# LANGUAGE TypeFamilies          #-}
+{-# OPTIONS_GHC -fno-warn-unused-top-binds #-}
+module Main (main) where
+
+import           Data.Text               (Text)
+import           Yesod
+import           Yesod.Form.Bulma
+
+data App = App
+
+mkYesod "App" [parseRoutes|
+/ HomeR GET POST
+|]
+
+instance Yesod App
+instance YesodBulma App
+
+instance RenderMessage App FormMessage where
+  renderMessage _ _ = defaultFormMessage
+
+data Basic = Basic
+  { name     :: Text
+  , username :: Text
+  , email    :: Text
+  , subject  :: Text
+  , message  :: Textarea
+  , agree    :: Bool
+  , question :: Text
+  }
+
+basicForm :: Html -> MForm Handler (FormResult Basic, Widget)
+basicForm = renderBulma BulmaBasicForm $ Basic
+  <$> areq bulmaTextField ("Text input" `withPlaceholder` "Name") Nothing
+  <*> areq bulmaTextField ("bulma" `withPlaceholder` "Username") Nothing
+  <*> areq bulmaEmailField ("Email input" `withPlaceholder` "Email") Nothing
+  <*> areq (bulmaSelectFieldList [("Select dropdown" :: Text, "v1"), ("With options", "v2")] ) "Subject" Nothing
+  <*> areq bulmaTextareaField ("Textarea" `withPlaceholder` "Message") Nothing
+  <*> areq (bulmaCheckBoxField "I agree to the terms and conditions") "" Nothing
+  <*> areq (bulmaRadioFieldList [("yes" :: Text, "y"), ("no", "n")]) "" Nothing
+  <*  bulmaSubmit (BulmaSubmit ("Submit" :: Text) "btn-default" [("attribute-name", "attribute-value")])
+
+getHomeR :: Handler Html
+getHomeR = do
+  ((result, form1), enctype) <- runFormPost basicForm
+
+  defaultLayout $
+    case result of
+      FormSuccess res ->
+        [whamlet|
+          <section .section .columns>
+            <div .container .column .is-4>
+              <form method=post action=@{HomeR} enctype=#{enctype}>
+                ^{form1}
+
+            <div .container .column .is-4>
+              <table .table>
+                <tr><th>Name</th><td>#{name res}</td></tr>
+                <tr><th>Username</th><td>#{username res}</td></tr>
+                <tr><th>Email</th><td>#{email res}</td></tr>
+                <tr><th>Subject</th><td>#{subject res}</td></tr>
+                <tr><th>Message</th><td>#{message res}</td></tr>
+                <tr><th>Agree</th><td>#{agree res}</td></tr>
+                <tr><th>Question</th><td>#{question res}</td></tr>
+        |]
+      _ ->
+        [whamlet|
+          <section .section>
+            <div .container>
+              <form method=post action=@{HomeR} enctype=#{enctype}>
+                ^{form1}
+        |]
+
+postHomeR :: Handler Html
+postHomeR = getHomeR
+
+main :: IO ()
+main = warp 3100 App
diff --git a/app/Showcase/Main.hs b/app/Showcase/Main.hs
new file mode 100644
--- /dev/null
+++ b/app/Showcase/Main.hs
@@ -0,0 +1,93 @@
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings     #-}
+{-# LANGUAGE QuasiQuotes           #-}
+{-# LANGUAGE TemplateHaskell       #-}
+{-# LANGUAGE TypeFamilies          #-}
+{-# OPTIONS_GHC -fno-warn-unused-top-binds #-}
+module Main (main) where
+
+import           Control.Arrow    ((&&&))
+import           Data.Text        (Text, pack)
+import           Yesod
+import           Yesod.Form.Bulma
+
+data App = App
+
+mkYesod "App" [parseRoutes|
+/ HomeR GET POST
+|]
+
+instance Yesod App
+instance YesodBulma App
+
+instance RenderMessage App FormMessage where
+  renderMessage _ _ = defaultFormMessage
+
+data Basic = Basic
+  { getTextField       :: Text
+  -- , getPasswordField :: Text
+  , getTextareaField   :: Textarea
+  -- , getHiddenField  :: Text
+  , getIntField        :: Int
+  -- , getDayField    :: Day
+  -- , getTimeFieldTypeTime :: Text
+  -- , getTimeFieldTypeText
+  -- , getHtmlField
+  , getEmailField      :: Text
+  -- , getMultiEmailField
+  -- , getSearchField
+  -- , getUrlField
+  -- , getDoubleField
+  -- , getBoolField
+  , getCheckBoxField   :: Bool
+  -- , getFileField
+  , getSelectField     :: Color
+  , getSelectFieldList :: Color
+  , getRadioField :: Color
+  , getRadioFieldList :: Color
+  , getCheckboxesField :: [Color]
+  , getCheckboxesFieldList :: [Color]
+  , getMultiSelectField :: [Color]
+  , getMultiSelectFieldList :: [Color]
+  }
+
+data Color = Red | Blue | Gray | Black
+  deriving (Show, Eq, Enum, Bounded)
+
+colors :: [(Text, Color)]
+colors = map (pack . show &&& id) [minBound .. maxBound]
+
+basicForm :: Html -> MForm Handler (FormResult Basic, Widget)
+basicForm = renderBulma BulmaBasicForm $ Basic
+  <$> areq bulmaTextField "bulmaTextField" Nothing
+  <*> areq bulmaTextareaField "bulmaTextareaField" Nothing
+  <*> areq bulmaIntField "bulmaIntField" Nothing
+  <*> areq bulmaEmailField "bulmaEmailField" Nothing
+  <*> areq (bulmaCheckBoxField "bulmaCheckBoxField") "" Nothing
+  <*> areq (bulmaSelectField optionsEnum) "bulmaSelectField" Nothing
+  <*> areq (bulmaSelectFieldList colors) "bulmaSelectFieldList" Nothing
+  <*> areq (bulmaRadioFieldList colors) "bulmaRadioList" Nothing
+  <*> areq (bulmaRadioFieldList colors) "bulmaRadioFieldList" Nothing
+  <*> areq (bulmaCheckboxesField optionsEnum) "bulmaCheckboxesField" Nothing
+  <*> areq (bulmaCheckboxesFieldList colors) "bulmaCheckboxesFieldList" Nothing
+  <*> areq (bulmaMultiSelectField optionsEnum) "bulmaMultiSelectField" Nothing
+  <*> areq (bulmaMultiSelectFieldList colors) "bulmaMultiSelectFieldList" Nothing
+  <*  bulmaSubmit (BulmaSubmit ("Submit" :: Text) "btn-default" [("attribute-name", "attribute-value")])
+
+getHomeR :: Handler Html
+getHomeR = do
+  ((_result, form1), enctype) <- runFormPost basicForm
+
+  defaultLayout
+    [whamlet| $newline never
+      <section .section>
+        <div .container>
+          <form method=post action=@{HomeR} enctype=#{enctype}>
+            ^{form1}
+    |]
+
+postHomeR :: Handler Html
+postHomeR = getHomeR
+
+main :: IO ()
+main = warp 3100 App
diff --git a/src/Yesod/Form/Bulma.hs b/src/Yesod/Form/Bulma.hs
new file mode 100644
--- /dev/null
+++ b/src/Yesod/Form/Bulma.hs
@@ -0,0 +1,101 @@
+{-# LANGUAGE FlexibleContexts      #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings     #-}
+{-# LANGUAGE QuasiQuotes           #-}
+{-# LANGUAGE TypeFamilies          #-}
+module Yesod.Form.Bulma
+  ( module Yesod.Form.Bulma.Fields
+  , module Yesod.Form.Bulma.Class
+  , renderBulma
+  , bulmaSubmit
+  , BulmaSubmit(..)
+  , BulmaFormLayout(..)
+  , withPlaceholder
+  ) where
+
+import           Data.Bifunctor
+import           Data.Text               (Text)
+import           Text.Shakespeare.I18N
+import           Yesod.Core
+import           Yesod.Form.Bulma.Class
+import           Yesod.Form.Bulma.Fields
+import           Yesod.Form.Bulma.Utils
+import           Yesod.Form.Functions
+import           Yesod.Form.Types
+
+data BulmaFormLayout = BulmaBasicForm
+
+data BulmaSubmit msg =
+  BulmaSubmit
+    { _bulmaValue   :: msg -- ^ The text of the submit button.
+    , _bulmaClasses :: Text -- ^ Classes added to the @\<button>@.
+    , _bulmaAttrs   :: [(Text, Text)] -- ^ Attributes added to the @\<button>@.
+    } deriving Show
+
+renderBulma :: YesodBulma site => BulmaFormLayout -> FormRender (HandlerFor site) a
+renderBulma formLayout aform fragment = do
+  (res, views') <- aFormToForm aform
+  let
+    views = views' []
+    widget = do
+      addStylesheet' urlBulmaCss
+      addScript' urlFontawesomeJs
+      _cancelId <- newIdent
+      [whamlet| $newline never
+        #{fragment}
+        $forall view <- views
+          $if fvId view == bulmaSubmitId
+            <div .field .is-grouped>
+              <div .control>
+                <button .button .is-link>Submit
+          $else
+            <div .field
+                 :fvRequired view:.required
+                 :not $ fvRequired view:.optional
+                 :has $ fvErrors view:.is-danger>
+              $case formLayout
+                $of BulmaBasicForm
+                  <label .label for=#{fvId view}>#{fvLabel view}
+                  <div .control>
+                    ^{fvInput view}
+                    ^{helpWidget view}
+      |]
+  return (res, widget)
+  where
+    has (Just _) = True
+    has Nothing  = False
+
+bulmaSubmit :: (RenderMessage site msg, HandlerSite m ~ site, MonadHandler m) => BulmaSubmit msg -> AForm m ()
+bulmaSubmit= formToAForm . fmap (second return) . mbulmaSubmit
+
+mbulmaSubmit
+    :: (RenderMessage site msg, HandlerSite m ~ site, MonadHandler m)
+    => BulmaSubmit msg -> MForm m (FormResult (), FieldView site)
+mbulmaSubmit (BulmaSubmit msg classes attrs) =
+    let res = FormSuccess ()
+        widget = [whamlet|$newline never
+            <button class="btn #{classes}" type=submit *{attrs}>_{msg}
+          |]
+        fv  = FieldView { fvLabel    = ""
+                        , fvTooltip  = Nothing
+                        , fvId       = bulmaSubmitId
+                        , fvInput    = widget
+                        , fvErrors   = Nothing
+                        , fvRequired = False }
+    in return (res, fv)
+
+-- | (Internal) Render a help widget for tooltips and errors.
+helpWidget :: FieldView site -> WidgetFor site ()
+helpWidget view = [whamlet|
+    $maybe tt <- fvTooltip view
+      <span .help-block>#{tt}
+    $maybe err <- fvErrors view
+      <span .help-block .error-block>#{err}
+|]
+
+bulmaSubmitId :: Text
+bulmaSubmitId = "b:ulma___unique__:::::::::::::::::submit-id"
+
+withPlaceholder :: Text -> FieldSettings site -> FieldSettings site
+withPlaceholder placeholder fs = fs { fsAttrs = newAttrs }
+  where newAttrs = ("placeholder", placeholder) : fsAttrs fs
diff --git a/src/Yesod/Form/Bulma/Class.hs b/src/Yesod/Form/Bulma/Class.hs
new file mode 100644
--- /dev/null
+++ b/src/Yesod/Form/Bulma/Class.hs
@@ -0,0 +1,20 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Yesod.Form.Bulma.Class
+  ( YesodBulma
+  , urlBulmaCss
+  , urlBulmaExCheckRadio
+  , urlFontawesomeJs
+  ) where
+
+import           Data.Text  (Text)
+import           Yesod.Core
+
+class YesodBulma a where
+  urlBulmaCss :: a -> Either (Route a) Text
+  urlBulmaCss _ = Right "//cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css"
+
+  urlBulmaExCheckRadio :: a -> Either (Route a) Text
+  urlBulmaExCheckRadio _ = Right "//cdn.jsdelivr.net/npm/bulma-extensions@1.0.30/bulma-checkradio/dist/bulma-checkradio.min.css"
+
+  urlFontawesomeJs :: a -> Either (Route a) Text
+  urlFontawesomeJs _ = Right "//use.fontawesome.com/releases/v5.0.13/js/all.js"
diff --git a/src/Yesod/Form/Bulma/Fields.hs b/src/Yesod/Form/Bulma/Fields.hs
new file mode 100644
--- /dev/null
+++ b/src/Yesod/Form/Bulma/Fields.hs
@@ -0,0 +1,316 @@
+{-# LANGUAGE ExplicitForAll        #-}
+{-# LANGUAGE FlexibleContexts      #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings     #-}
+{-# LANGUAGE QuasiQuotes           #-}
+module Yesod.Form.Bulma.Fields
+  ( bulmaIntField
+  , bulmaTextField
+  , bulmaEmailField
+  , bulmaTextareaField
+  , bulmaCheckBoxField
+  , bulmaRadioFieldList
+  , bulmaRadioField
+  , bulmaSelectFieldList
+  , bulmaSelectField
+  , bulmaCheckboxesFieldList
+  , bulmaCheckboxesField
+  , bulmaMultiSelectFieldList
+  , bulmaMultiSelectField
+  ) where
+
+import           Control.Arrow            ((&&&))
+import           Control.Monad            (forM_, unless)
+import           Data.Maybe               (listToMaybe)
+import           Data.Text                (Text, pack)
+import           Data.Text.Encoding       (decodeUtf8With, encodeUtf8)
+import           Data.Text.Encoding.Error (lenientDecode)
+import           Data.Text.Read           (decimal, signed)
+import qualified Text.Email.Validate      as Email
+import           Text.Shakespeare.I18N    (RenderMessage, SomeMessage (..))
+import           Yesod.Core               (HandlerSite)
+import           Yesod.Core.Types         (HandlerFor, WidgetFor)
+import           Yesod.Core.Widget        (handlerToWidget, whamlet)
+import           Yesod.Form.Bulma.Class
+import           Yesod.Form.Bulma.Utils   (addStylesheet')
+import           Yesod.Form.Fields        (FormMessage (..), Option (..),
+                                           OptionList (..), Textarea (..),
+                                           optionsPairs)
+import           Yesod.Form.Functions     (parseHelper)
+import           Yesod.Form.Types         (Enctype (..), Field (..))
+
+-- | Creates an input with @type="checkbox"@ for selecting multiple options.
+bulmaCheckboxesFieldList
+  :: ( YesodBulma site
+     , Eq a
+     , RenderMessage site msg
+     )
+  => [(msg, a)] -> Field (HandlerFor site) [a]
+bulmaCheckboxesFieldList = bulmaCheckboxesField . optionsPairs
+
+-- | Creates an input with @type="checkbox"@ for selecting multiple options.
+bulmaCheckboxesField
+  :: ( YesodBulma site
+     , Eq a
+     )
+  => HandlerFor site (OptionList a) -> Field (HandlerFor site) [a]
+bulmaCheckboxesField ioptlist = (bulmaMultiSelectField ioptlist)
+  { fieldView = \theId name attrs val _isReq -> do
+      opts <- olOptions <$> handlerToWidget ioptlist
+      let
+        optselected (Left _) _       = False
+        optselected (Right vals) opt = optionInternalValue opt `elem` vals
+      addStylesheet' urlBulmaExCheckRadio
+      [whamlet| $newline never
+        <div ##{theId}>
+          $forall opt <- opts
+            <input .is-checkradio type=checkbox id=#{name}-#{optionExternalValue opt} name=#{name} value=#{optionExternalValue opt} *{attrs} :optselected val opt:checked>
+            <label for=#{name}-#{optionExternalValue opt}>#{optionDisplay opt}
+      |]
+  }
+
+-- | Creates a @\<select>@ tag for selecting multiple options.
+bulmaMultiSelectFieldList
+  :: ( Eq a
+     , RenderMessage site msg
+     )
+  => [(msg, a)] -> Field (HandlerFor site) [a]
+bulmaMultiSelectFieldList = bulmaMultiSelectField . optionsPairs
+
+-- | Creates a @\<select>@ tag for selecting multiple options.
+bulmaMultiSelectField
+  :: Eq a
+  => HandlerFor site (OptionList a) -> Field (HandlerFor site) [a]
+bulmaMultiSelectField ioptlist = Field parse view UrlEncoded
+ where
+  parse []      _ = return $ Right Nothing
+  parse optlist _ = do
+    mapopt <- olReadExternal <$> ioptlist
+    case mapM mapopt optlist of
+      Nothing  -> return $ Left "Error parsing values"
+      Just res -> return $ Right $ Just res
+
+  view theId name attrs val isReq = do
+    opts <- olOptions <$> handlerToWidget ioptlist
+    let selOpts = map (id &&& optselected val) opts
+    [whamlet| $newline never
+      <div .select .is-multiple>
+        <select ##{theId} name=#{name} :isReq:required multiple size=#{min 5 (length selOpts)} *{attrs}>
+          $forall (opt, optsel) <- selOpts
+            <option value=#{optionExternalValue opt} :optsel:selected>#{optionDisplay opt}
+    |]
+    where
+      optselected (Left _) _       = False
+      optselected (Right vals) opt = optionInternalValue opt `elem` vals
+
+-- | Creates a input with @type="number"@ and @step=1@.
+bulmaIntField
+  :: ( Monad m
+     , Integral i
+     , RenderMessage (HandlerSite m) FormMessage
+     )
+  => Field m i
+bulmaIntField = Field
+  { fieldParse = parseHelper $ \s ->
+    case signed decimal s of
+      Right (a, "") -> Right a
+      _             -> Left $ MsgInvalidInteger s
+  , fieldView = \theId name attrs val isReq ->
+      [whamlet| $newline never
+        <input id="#{theId}" .input name="#{name}" *{attrs} type="number" step=1 :isReq:required="" value="#{showVal val}">
+      |]
+  , fieldEnctype = UrlEncoded
+  }
+  where
+    showVal = either id (pack . showI)
+    showI x = show (fromIntegral x :: Integer)
+
+-- | Creates a input with @type="text"@.
+bulmaTextField
+  :: ( Monad m
+     , RenderMessage (HandlerSite m) FormMessage
+     )
+  => Field m Text
+bulmaTextField = Field
+  { fieldParse = parseHelper Right
+  , fieldView = \theId name attrs val isReq ->
+      [whamlet| $newline never
+        <input id="#{theId}" .input name="#{name}" *{attrs} type="text" :isReq:required value="#{either id id val}">
+      |]
+  , fieldEnctype = UrlEncoded
+  }
+
+-- | 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").
+bulmaEmailField
+  :: ( Monad m
+     , RenderMessage (HandlerSite m) FormMessage
+     )
+  => Field m Text
+bulmaEmailField = Field
+  { fieldParse = parseHelper $
+    \s ->
+      case Email.canonicalizeEmail $ encodeUtf8 s of
+        Just e  -> Right $ decodeUtf8With lenientDecode e
+        Nothing -> Left $ MsgInvalidEmail s
+  , fieldView = \theId name attrs val isReq ->
+      [whamlet| $newline never
+        <input id="#{theId}" .input name="#{name}" *{attrs} type="email" :isReq:required="" value="#{either id id val}">
+      |]
+  , fieldEnctype = UrlEncoded
+  }
+
+-- | Creates a @\<textarea>@ tag whose returned value is wrapped in a 'Textarea'; see 'Textarea' for details.
+bulmaTextareaField
+  :: ( Monad m
+     , RenderMessage (HandlerSite m) FormMessage
+     )
+  => Field m Textarea
+bulmaTextareaField = Field
+  { fieldParse = parseHelper $ Right . Textarea
+  , fieldView = \theId name attrs val isReq ->
+      [whamlet| $newline never
+        <textarea id="#{theId}" .textarea name="#{name}" :isReq:required="" *{attrs}>#{either id unTextarea val}
+      |]
+  , fieldEnctype = UrlEncoded
+  }
+
+-- | 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.
+--
+bulmaCheckBoxField
+  :: YesodBulma site
+  => Text -> Field (HandlerFor site) Bool
+bulmaCheckBoxField msg = Field
+  { fieldParse = \e _ -> return $ checkBoxParser e
+  , fieldView  = \theId name attrs val _ -> do
+      addStylesheet' urlBulmaExCheckRadio
+      [whamlet| $newline never
+        <input .is-checkradio id=#{theId} *{attrs} type=checkbox name=#{name} value=yes :showVal id val:checked>
+        <label for=#{theId}>#{msg}
+      |]
+  , fieldEnctype = UrlEncoded
+  }
+  where
+    checkBoxParser [] = Right $ Just False
+    checkBoxParser (x:_) = case x of
+        "yes" -> Right $ Just True
+        "on"  -> Right $ Just True
+        _     -> Right $ Just False
+    showVal = either (const False)
+
+-- | Creates an input with @type="radio"@ for selecting one option.
+bulmaRadioFieldList
+  :: ( YesodBulma site
+     , Eq a
+     , RenderMessage site FormMessage
+     , RenderMessage site msg
+     )
+  => [(msg, a)] -> Field (HandlerFor site) a
+bulmaRadioFieldList = bulmaRadioField . optionsPairs
+
+-- | Creates an input with @type="radio"@ for selecting one option.
+bulmaRadioField
+  :: ( YesodBulma site
+     , Eq a
+     , RenderMessage site FormMessage
+     )
+  => HandlerFor site (OptionList a) -> Field (HandlerFor site) a
+bulmaRadioField = selectFieldHelper
+  (\theId _name _attrs inside -> do
+    addStylesheet' urlBulmaExCheckRadio
+    [whamlet| $newline never
+      <div ##{theId}>^{inside}
+    |])
+  (\theId name isSel -> do
+    addStylesheet' urlBulmaExCheckRadio
+    [whamlet| $newline never
+      <input .is-checkradio id=#{theId}-none type=radio name=#{name} value=none :isSel:checked>
+      <labelfor=#{theId}-none>_{MsgSelectNone}
+    |])
+  (\theId name attrs value isSel text -> do
+    addStylesheet' urlBulmaExCheckRadio
+    [whamlet| $newline never
+      <input .is-checkradio id=#{theId}-#{value} type=radio name=#{name} value=#{value} :isSel:checked *{attrs}>
+      <label for=#{theId}-#{value}>#{text}
+    |])
+
+-- | Creates a @\<select>@ tag for selecting one option. Example usage:
+--
+-- > areq (selectFieldList [("Value 1" :: Text, "value1"),("Value 2", "value2")]) "Which value?" Nothing
+bulmaSelectFieldList
+  :: ( Eq a
+     , RenderMessage site FormMessage
+     , RenderMessage site msg
+     )
+  => [(msg, a)] -> Field (HandlerFor site) a
+bulmaSelectFieldList = bulmaSelectField . optionsPairs
+
+-- | Creates a @\<select>@ tag for selecting one option. Example usage:
+--
+-- > areq (selectField $ optionsPairs [(MsgValue1, "value1"),(MsgValue2, "value2")]) "Which value?" Nothing
+bulmaSelectField
+  :: (Eq a, RenderMessage site FormMessage)
+  => HandlerFor site (OptionList a)
+  -> Field (HandlerFor site) a
+bulmaSelectField = selectFieldHelper
+  (\theId name attrs inside ->
+    [whamlet| $newline never
+      <div .select>
+        <select ##{theId} name=#{name} *{attrs}>
+          ^{inside}
+    |]) -- outside
+  (\_theId _name isSel ->
+    [whamlet| $newline never
+      <option value=none :isSel:selected>_{MsgSelectNone}
+    |]) -- onOpt
+  (\_theId _name _attrs value isSel text ->
+    [whamlet| $newline never
+      <option value=#{value} :isSel:selected>#{text}
+    |]) -- inside
+
+-- port from Yesod.Form.Fields
+selectFieldHelper
+  :: ( Eq a
+     , RenderMessage site FormMessage
+     )
+  => (Text -> Text -> [(Text, Text)] -> WidgetFor site () -> WidgetFor site ())
+  -> (Text -> Text -> Bool -> WidgetFor site ())
+  -> (Text -> Text -> [(Text, Text)] -> Text -> Bool -> Text -> WidgetFor site ())
+  -> HandlerFor site (OptionList a)
+  -> Field (HandlerFor site) a
+selectFieldHelper outside onOpt inside opts' = Field
+  { fieldParse   = \x _ -> do
+    opts <- opts'
+    return $ selectParser opts x
+  , fieldView    = \theId name attrs val isReq -> do
+    opts <- olOptions <$> handlerToWidget opts'
+    outside theId name attrs $ do
+      unless isReq $ onOpt theId name $ notElem (render opts val) $ map
+        optionExternalValue
+        opts
+      forM_ opts $ \opt -> inside
+        theId
+        name
+        ((if isReq then (("required", "required") :) else id) attrs)
+        (optionExternalValue opt)
+        (render opts val == optionExternalValue opt)
+        (optionDisplay opt)
+  , fieldEnctype = UrlEncoded
+  }
+  where
+    render _    (Left  _) = ""
+    render opts (Right a) = maybe "" optionExternalValue $ listToMaybe $ filter
+      ((== a) . optionInternalValue)
+      opts
+    selectParser _    []      = Right Nothing
+    selectParser opts (s : _) = case s of
+      ""     -> Right Nothing
+      "none" -> Right Nothing
+      x      -> case olReadExternal opts x of
+        Nothing -> Left $ SomeMessage $ MsgInvalidEntry x
+        Just y  -> Right $ Just y
diff --git a/src/Yesod/Form/Bulma/Utils.hs b/src/Yesod/Form/Bulma/Utils.hs
new file mode 100644
--- /dev/null
+++ b/src/Yesod/Form/Bulma/Utils.hs
@@ -0,0 +1,25 @@
+{-# LANGUAGE TypeFamilies #-}
+module Yesod.Form.Bulma.Utils
+  ( addStylesheet'
+  , addScript'
+  )
+where
+
+import           Data.Text  (Text)
+import           Yesod.Core
+
+addStylesheet'
+  :: (MonadWidget m, HandlerSite m ~ site)
+  => (site -> Either (Route site) Text)
+  -> m ()
+addStylesheet' f = do
+  y <- getYesod
+  addStylesheetEither $ f y
+
+addScript'
+  :: (HandlerSite m ~ site, MonadWidget m)
+  => (site -> Either (Route site) Text)
+  -> m ()
+addScript' f = do
+  y <- getYesod
+  addScriptEither $ f y
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,2 @@
+main :: IO ()
+main = putStrLn "Test suite not yet implemented"
diff --git a/yesod-form-bulma.cabal b/yesod-form-bulma.cabal
new file mode 100644
--- /dev/null
+++ b/yesod-form-bulma.cabal
@@ -0,0 +1,101 @@
+-- This file has been generated from package.yaml by hpack version 0.28.2.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: d93f511a61b406fbcb3446ab5cb6827e3f31b12825441e6ffd166219d9c555c4
+
+name:           yesod-form-bulma
+version:        0.1.0.0
+synopsis:       support Bulma form for Yesod
+description:    Please see the README on Github at <https://github.com/waddlaw/yesod-form-bulma#readme>
+category:       Web, Yesod
+homepage:       https://github.com/waddlaw/yesod-form-bulma#readme
+bug-reports:    https://github.com/waddlaw/yesod-form-bulma/issues
+author:         Shinya Yamaguchi
+maintainer:     ingroze@gmail.com
+copyright:      Copyright (c) 2018 Shinya Yamaguchi
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
+extra-source-files:
+    ChangeLog.md
+    README.md
+
+source-repository head
+  type: git
+  location: https://github.com/waddlaw/yesod-form-bulma
+
+library
+  exposed-modules:
+      Yesod.Form.Bulma
+      Yesod.Form.Bulma.Class
+      Yesod.Form.Bulma.Fields
+      Yesod.Form.Bulma.Utils
+  other-modules:
+      Paths_yesod_form_bulma
+  hs-source-dirs:
+      src
+  ghc-options: -Wall -Wcompat -Wincomplete-uni-patterns -Wincomplete-record-updates -Wnoncanonical-monad-instances -Wredundant-constraints -Wtabs
+  build-depends:
+      base >=4.7 && <5
+    , email-validate
+    , shakespeare
+    , text
+    , yesod-core
+    , yesod-form
+  default-language: Haskell2010
+
+executable example
+  main-is: Main.hs
+  other-modules:
+      Paths_yesod_form_bulma
+  hs-source-dirs:
+      app/Example
+  ghc-options: -Wall -Wcompat -Wincomplete-uni-patterns -Wincomplete-record-updates -Wnoncanonical-monad-instances -Wredundant-constraints -Wtabs
+  build-depends:
+      base >=4.7 && <5
+    , email-validate
+    , shakespeare
+    , text
+    , yesod
+    , yesod-core
+    , yesod-form
+    , yesod-form-bulma
+  default-language: Haskell2010
+
+executable showcase
+  main-is: Main.hs
+  other-modules:
+      Paths_yesod_form_bulma
+  hs-source-dirs:
+      app/Showcase
+  ghc-options: -Wall -Wcompat -Wincomplete-uni-patterns -Wincomplete-record-updates -Wnoncanonical-monad-instances -Wredundant-constraints -Wtabs
+  build-depends:
+      base >=4.7 && <5
+    , email-validate
+    , shakespeare
+    , text
+    , yesod
+    , yesod-core
+    , yesod-form
+    , yesod-form-bulma
+  default-language: Haskell2010
+
+test-suite yesod-form-bulma-test
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  other-modules:
+      Paths_yesod_form_bulma
+  hs-source-dirs:
+      test
+  ghc-options: -Wall -Wcompat -Wincomplete-uni-patterns -Wincomplete-record-updates -Wnoncanonical-monad-instances -Wredundant-constraints -Wtabs -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.7 && <5
+    , email-validate
+    , shakespeare
+    , text
+    , yesod-core
+    , yesod-form
+    , yesod-form-bulma
+  default-language: Haskell2010
