diff --git a/src/Yesod/Bootstrap.hs b/src/Yesod/Bootstrap.hs
deleted file mode 100644
--- a/src/Yesod/Bootstrap.hs
+++ /dev/null
@@ -1,596 +0,0 @@
-module Yesod.Bootstrap where
-
-import Prelude hiding (div)
-import Data.Foldable
-import Yesod.Core
-import Yesod.Core.Widget
-import Yesod.Core.Handler
-import Data.Text (Text)
-import Data.List
-import Data.Monoid
-import Control.Monad
-import Text.Blaze.Html (toHtml)
-import qualified Data.Text as Text
-import Control.Monad.Writer.Class
-import Control.Monad.Writer.Strict
-import qualified Data.List as List
-import qualified Text.Blaze.Html5 as H
-import qualified Text.Blaze.Html5.Attributes as HA
-import Data.Function (on)
-import Data.String (IsString(..))
-import Data.Char (isDigit)
-import Text.Julius (rawJS)
-
-data Context = Success | Info | Warning | Danger | Default | Primary | Link | Error
-data Size = ExtraSmall | Small | Medium | Large
-data ColSize = ColSize Size Int
-data Flow = Block | Inline
-data Panel site = Panel 
-  { panelTitle :: (WidgetT site IO ()) 
-  , panelBody :: (WidgetT site IO ())
-  , panelContext :: Context
-  }
-
-basicPanel :: Text -> WidgetT site IO () -> Panel site
-basicPanel t c = Panel (tw t) c Default
-
-div_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-div_ attrs inner = [whamlet|<div *{mkStrAttrs attrs}>^{inner}|]
-
-span_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-span_ attrs inner = [whamlet|<span *{mkStrAttrs attrs}>^{inner}|]
-
-strong_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-strong_ attrs inner = [whamlet|$newline never
-<strong *{mkStrAttrs attrs}>^{inner}|]
-
-em_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-em_ attrs inner = [whamlet|$newline never
-<em *{mkStrAttrs attrs}>^{inner}|]
-
-s_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-s_ attrs inner = [whamlet|<s *{mkStrAttrs attrs}>^{inner}|]
-
-nav_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-nav_ attrs inner = [whamlet|<nav *{mkStrAttrs attrs}>^{inner}|]
-
-form_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-form_ attrs inner = [whamlet|<form *{mkStrAttrs attrs}>^{inner}|]
-
-script_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-script_ attrs inner = [whamlet|<script *{mkStrAttrs attrs}>^{inner}|]
-
-label_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-label_ attrs inner = [whamlet|<label *{mkStrAttrs attrs}>^{inner}|]
-
-pre_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-pre_ attrs inner = [whamlet|<pre *{mkStrAttrs attrs}>^{inner}|]
-
-code_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-code_ attrs inner = [whamlet|<code *{mkStrAttrs attrs}>^{inner}|]
-
-input_ :: [(Text,Text)] -> WidgetT site IO ()
-input_ attrs = [whamlet|<input *{mkStrAttrs attrs}>|]
-
-hr_ :: [(Text,Text)] -> WidgetT site IO ()
-hr_ attrs = [whamlet|<hr *{mkStrAttrs attrs}>|]
-
-br_ :: [(Text,Text)] -> WidgetT site IO ()
-br_ attrs = [whamlet|<br *{mkStrAttrs attrs}>|]
-
-img_ :: [(Text,Text)] -> WidgetT site IO ()
-img_ attrs = [whamlet|<img *{mkStrAttrs attrs}>|]
-
-textarea_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-textarea_ attrs inner = [whamlet|<textarea *{mkStrAttrs attrs}>^{inner}|]
-
-td_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-td_ attrs inner = [whamlet|<td *{mkStrAttrs attrs}>^{inner}|]
-
-th_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-th_ attrs inner = [whamlet|<th *{mkStrAttrs attrs}>^{inner}|]
-
-table_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-table_ attrs inner = [whamlet|<table *{mkStrAttrs attrs}>^{inner}|]
-
-tbody_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-tbody_ attrs inner = [whamlet|<tbody *{mkStrAttrs attrs}>^{inner}|]
-
-thead_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-thead_ attrs inner = [whamlet|<thead *{mkStrAttrs attrs}>^{inner}|]
-
-tr_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-tr_ attrs inner = [whamlet|<tr *{mkStrAttrs attrs}>^{inner}|]
-
-h1_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-h1_ attrs inner = [whamlet|<h1 *{mkStrAttrs attrs}>^{inner}|]
-
-h2_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-h2_ attrs inner = [whamlet|<h2 *{mkStrAttrs attrs}>^{inner}|]
-
-h3_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-h3_ attrs inner = [whamlet|<h3 *{mkStrAttrs attrs}>^{inner}|]
-
-h4_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-h4_ attrs inner = [whamlet|<h4 *{mkStrAttrs attrs}>^{inner}|]
-
-h5_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-h5_ attrs inner = [whamlet|<h5 *{mkStrAttrs attrs}>^{inner}|]
-
-h6_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-h6_ attrs inner = [whamlet|<h6 *{mkStrAttrs attrs}>^{inner}|]
-
-p_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-p_ attrs inner = [whamlet|<p *{mkStrAttrs attrs}>^{inner}|]
-
-ul_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-ul_ attrs inner = [whamlet|<ul *{mkStrAttrs attrs}>^{inner}|]
-
-ol_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-ol_ attrs inner = [whamlet|<ol *{mkStrAttrs attrs}>^{inner}|]
-
-li_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-li_ attrs inner = [whamlet|<li *{mkStrAttrs attrs}>^{inner}|]
-
-blockquote_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-blockquote_ attrs inner = [whamlet|<blockquote *{mkStrAttrs attrs}>^{inner}|]
-
-small_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-small_ attrs inner = [whamlet|<small *{mkStrAttrs attrs}>^{inner}|]
-
-i_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-i_ attrs inner = [whamlet|<i *{mkStrAttrs attrs}>^{inner}|]
-
-a_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-a_ attrs inner = [whamlet|$newline never
-<a *{mkStrAttrs attrs}>^{inner}|]
-
-audio_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-audio_ attrs inner = [whamlet|<audio *{mkStrAttrs attrs}>^{inner}|]
-
-source_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-source_ attrs inner = [whamlet|<source *{mkStrAttrs attrs}>^{inner}|]
-
-anchor :: Route site -> WidgetT site IO () -> WidgetT site IO ()
-anchor route inner = [whamlet|<a href="@{route}">^{inner}|]
-
-anchorEmail :: Text -> WidgetT site IO () -> WidgetT site IO ()
-anchorEmail email inner = [whamlet|<a href="mailto:#{email}">^{inner}|]
-
-anchorPhone :: Text -> WidgetT site IO ()
-anchorPhone phone = [whamlet|<a href="tel:#{cleanedPhone}">#{phone}|]
-  where 
-  strippedPhone = Text.filter ((||) <$> isDigit <*> (== '+')) phone
-  cleanedPhone = case Text.uncons strippedPhone of
-    Nothing -> Text.empty
-    Just (c,cs) -> if c == '+' 
-      then strippedPhone
-      else Text.append "+1" strippedPhone
-
-button_ :: [(Text,Text)] -> WidgetT site IO () -> WidgetT site IO ()
-button_ attrs inner = [whamlet|<button *{mkStrAttrs attrs}>^{inner}|]
-
-mkStrAttrs :: [(Text,Text)] -> [(String,String)]
-mkStrAttrs = map $ \(a,b) -> (Text.unpack a, Text.unpack b)
-
-row :: WidgetT site IO () -> WidgetT site IO ()
-row = div_ [("class","row")]
-
-container :: WidgetT site IO () -> WidgetT site IO ()
-container = div_ [("class","container")]
-
-well :: Size -> WidgetT site IO () -> WidgetT site IO ()
-well size = div_ [("class","well well-" <> colSizeShortName size)]
-
-col :: [ColSize] -> WidgetT site IO () -> WidgetT site IO ()
-col cs = div_ [("class", Text.intercalate " " (map mkAttr cs))]
-  where mkAttr (ColSize s n) = Text.concat ["col-", colSizeShortName s, "-", Text.pack (show n)]
-
-checkbox :: WidgetT site IO () -> WidgetT site IO ()
-checkbox = div_ [("class","checkbox")]
-
-alert :: Context -> WidgetT site IO () -> WidgetT site IO ()
-alert ctx = div_ [("class","alert alert-" <> contextName ctx)]
-
-alertHtml :: Context -> Html -> Html
-alertHtml ctx inner = H.div H.! HA.class_ (fromString $ Text.unpack $ "alert alert-" <> contextName ctx) $ inner
-
-alertHtmlDismiss :: Context -> Html -> Html
-alertHtmlDismiss ctx inner = H.div H.! HA.class_ (fromString $ Text.unpack $ "alert alert-dismissable alert-" <> contextName ctx) $ do
-  H.button H.! HA.class_ "close" H.! HA.type_ "button" H.! H.dataAttribute "dismiss" "alert" $ H.preEscapedToHtml ("&times;" :: Text)
-  inner
-
-caret :: WidgetT site IO ()
-caret = span_ [("class","caret")] mempty
-
-glyphicon :: Text -> WidgetT site IO ()
-glyphicon s = span_ [("class","glyphicon glyphicon-" <> s)] mempty
-
-glyphiconFeedback :: Text -> WidgetT site IO ()
-glyphiconFeedback s = span_ [("class",Text.concat ["glyphicon glyphicon-", s, " form-control-feedback"])] mempty
-
-formGroup :: WidgetT site IO () -> WidgetT site IO ()
-formGroup = div_ [("class","form-group")]
-
-formGroupFeedback :: Context -> WidgetT site IO () -> WidgetT site IO ()
-formGroupFeedback ctx = div_ [("class",Text.concat ["form-group has-", contextName ctx, " has-feedback"])]
-
-inputGroup :: WidgetT site IO () -> WidgetT site IO ()
-inputGroup = div_ [("class","input-group")] 
-
-inputGroupAddon :: WidgetT site IO () -> WidgetT site IO ()
-inputGroupAddon = span_ [("class","input-group-addon")] 
-
-controlLabel :: WidgetT site IO () -> WidgetT site IO ()
-controlLabel = label_ [("class","control-label")]
-
-helpBlock :: WidgetT site IO () -> WidgetT site IO ()
-helpBlock = div_ [("class","help-block")]
-
-button :: Context -> Size -> WidgetT site IO () -> WidgetT site IO ()
-button ctx size inner = do
-  button_ [("class","btn btn-" <> contextName ctx <> " btn-" <> colSizeShortName size)] inner
-
-buttonRaised :: Context -> Size -> WidgetT site IO () -> WidgetT site IO ()
-buttonRaised ctx size inner = do
-  button_ [("class","btn btn-raised btn-" <> contextName ctx <> " btn-" <> colSizeShortName size)] inner
-
-buttonRaisedBlock :: Context -> Size -> WidgetT site IO () -> WidgetT site IO ()
-buttonRaisedBlock ctx size inner = do
-  button_ [("class","btn btn-raised btn-block btn-" <> contextName ctx <> " btn-" <> colSizeShortName size)] inner
-
-formButtonPost :: Context -> Size -> Route site -> WidgetT site IO () -> WidgetT site IO ()
-formButtonPost ctx size route inner = do
-  render <- getUrlRender
-  form_ [("method","POST"),("action",render route)] $ do
-    button ctx size inner
-
-formButtonRaisedPost :: Context -> Size -> Route site -> WidgetT site IO () -> WidgetT site IO ()
-formButtonRaisedPost ctx size route inner = do
-  render <- getUrlRender
-  form_ [("method","POST"),("action",render route)] $ do
-    buttonRaised ctx size inner
-
-formButtonRaisedPostBlock :: Context -> Size -> Route site -> WidgetT site IO () -> WidgetT site IO ()
-formButtonRaisedPostBlock ctx size route inner = do
-  render <- getUrlRender
-  form_ [("method","POST"),("action",render route)] $ do
-    buttonRaisedBlock ctx size inner
-
-anchorButton :: Context -> Size -> Route site -> WidgetT site IO () -> WidgetT site IO ()
-anchorButton ctx size route inner = do
-  render <- getUrlRender
-  a_ [("href",render route),("class","btn btn-" <> contextName ctx <> " btn-" <> colSizeShortName size)] inner
-
-anchorButtonDropdown :: Context -> Size -> WidgetT site IO () -> [(Route site, WidgetT site IO ())] -> WidgetT site IO ()
-anchorButtonDropdown ctx size inner xs = div_ [("class","btn-group")] $ do
-  button_ [ ("type","button")
-          , ("class","btn btn-" <> contextName ctx <> " btn-" <> colSizeShortName size)
-          , ("data-toggle","dropdown")
-          , ("aria-haspopup","true")
-          , ("aria-expanded","false")
-          ] inner
-  ul_ [("class","dropdown-menu")] $ forM_ xs $ \(route,content) -> do
-    li_ [] $ anchor route content
-
-anchorButtonRaised :: Context -> Size -> Route site -> WidgetT site IO () -> WidgetT site IO ()
-anchorButtonRaised ctx size route inner = do
-  render <- getUrlRender
-  a_ [("href",render route),("class","btn btn-raised btn-" <> contextName ctx <> " btn-" <> colSizeShortName size)] inner
-
-anchorButtonBlock :: Context -> Size -> Route site -> WidgetT site IO () -> WidgetT site IO ()
-anchorButtonBlock ctx size route inner = do
-  render <- getUrlRender
-  a_ [("href",render route),("class","btn btn-block btn-" <> contextName ctx <> " btn-" <> colSizeShortName size)] inner
-
-anchorButtonRaisedBlock :: Context -> Size -> Route site -> WidgetT site IO () -> WidgetT site IO ()
-anchorButtonRaisedBlock ctx size route inner = do
-  render <- getUrlRender
-  a_ [("href",render route),("class","btn btn-raised btn-block btn-" <> contextName ctx <> " btn-" <> colSizeShortName size)] inner
-
-label :: Context -> WidgetT site IO () -> WidgetT site IO ()
-label ctx = span_ [("class","label label-" <> contextName ctx)]
-
-badge :: WidgetT site IO () -> WidgetT site IO ()
-badge = span_ [("class","badge")]
-
-panel :: Panel site -> WidgetT site IO ()
-panel (Panel title content ctx) = do
-  div_ [("class","panel panel-" <> contextName ctx)] $ do
-    div_ [("class", "panel-heading")] $ do
-      h4_ [("class","panel-title")] title
-    div_ [("class","panel-body")] $ do
-      content
-
-panelAccordion :: [Panel site] -> WidgetT site IO ()
-panelAccordion tcs = do 
-  groupId <- newIdent 
-  div_ [("class","panel-group"),("id",groupId),("role","tablist")] $ do
-    forM_ (zip [1..] tcs) $ \(i,Panel title content ctx) -> do
-      headingId <- newIdent
-      panelId <- newIdent
-      div_ [("class","panel panel-" <> contextName ctx)] $ do
-        div_ [("class", "panel-heading"),("role","tab"),("id",headingId)] $ do
-          h4_ [("class","panel-title")] $ do
-            a_ [("href","#" <> panelId),("role","button"),("data-toggle","collapse"),("data-parent","#" <> groupId)] $ do
-              title
-        div_ [("id",panelId),("class","panel-collapse collapse" <> (if i == 1 then " in" else "")),("role","tabpanel"),("aria-labelledby",headingId)] $ do
-          div_ [("class","panel-body")] $ do
-            content
-
-textSubmitGroupGetForm :: Route site -> Context -> Size -> Text -> Text -> Text -> WidgetT site IO () -> Bool -> WidgetT site IO ()
-textSubmitGroupGetForm route ctx size name placeholder value buttonContent buttonIsLeft = do
-  render <- getUrlRender
-  form_ [("method","GET"),("action",render route)] $ do
-    div_ [("class","form-group")] $ do
-      div_ [("class","input-group input-group-" <> colSizeShortName size)] 
-        $ mconcat
-        $ (if buttonIsLeft then reverse else id)
-        [ input_ [("class","form-control"),("type","text"),("name",name),("placeholder",placeholder),("value",value)]
-        , span_ [("class","input-group-btn")] $ do
-            button_ [("class","btn btn-" <> contextName ctx)] buttonContent
-        ]
-        
-
-colSizeShortName :: Size -> Text
-colSizeShortName s = case s of
-  ExtraSmall -> "xs" 
-  Small -> "sm" 
-  Medium -> "md" 
-  Large -> "lg" 
-
-contextName :: Context -> Text
-contextName c = case c of 
-  Success -> "success"
-  Info -> "info"
-  Warning -> "warning"
-  Default -> "default"
-  Primary -> "primary"
-  Link -> "link"
-  Error -> "error"
-  Danger -> "danger"
-
-data NavbarTheme = NavbarDefault | NavbarInverse | NavbarOtherTheme Text
-data NavbarPosition = NavbarStandard | NavbarStaticTop | NavbarFixedTop
-data NavbarItem site 
-  = NavbarLink (Route site) (WidgetT site IO ())
-  | NavbarDropdown (WidgetT site IO ()) [NavbarDropdownItem site]
-
-data NavbarDropdownItem site 
-  = NavbarDropdownLink (Route site) (WidgetT site IO ())
-  | NavbarDropdownHeader (WidgetT site IO ())
-  | NavbarDropdownSeparator
-
-navbar :: 
-     NavbarTheme
-  -> NavbarPosition 
-  -> Route site 
-  -> WidgetT site IO ()
-  -> [NavbarItem site]
-  -> [NavbarItem site]
-  -> WidgetT site IO ()
-navbar theme pos headerRoute headerContent items rightItems = do
-  navbarId <- newIdent
-  render <- getUrlRender
-  nav_ [("class","navbar " <> themeClass <> " " <> posClass)] $ do
-    div_ [("class",containerClass)] $ do
-      div_ [("class", "navbar-header")] $ do
-        button_ [ ("class", "navbar-toggle collapsed"),("type","button")
-                , ("data-toggle", "collapse"), ("aria-expanded", "false")
-                , ("aria-controls", navbarId),("data-target", "#" <> navbarId)
-                ] $ do
-          span_ [("class","sr-only")] $ tw "Toggle Navigation"
-          replicateM_ 3 $ span_ [("class","icon-bar")] mempty
-        a_ [("href", render headerRoute),("class","navbar-brand")] headerContent
-      div_ [("class","navbar-collapse collapse"), ("id", navbarId)] $ do
-        ul_ [("class","nav navbar-nav")] $ mapM_ navbarItem items
-        ul_ [("class","nav navbar-nav navbar-right")] $ mapM_ navbarItem rightItems
-  where 
-  themeClass = case theme of
-    NavbarDefault -> "navbar-default" 
-    NavbarInverse -> "navbar-inverse" 
-    NavbarOtherTheme t -> "navbar-" <> t
-  posClass = case pos of
-    NavbarStandard -> ""
-    NavbarStaticTop -> "navbar-static-top"
-    NavbarFixedTop -> "navbar-fixed-top"
-  containerClass = case pos of
-    NavbarStandard -> "container-fluid"
-    NavbarStaticTop -> "container"
-    NavbarFixedTop -> "container"
-  
-navbarItem :: NavbarItem site -> WidgetT site IO ()
-navbarItem item = do
-  render <- getUrlRender
-  li_ [] $ case item of
-    NavbarLink route name -> anchor route name
-    NavbarDropdown name children -> do
-      a_ [ ("class","dropdown-toggle"), ("href", "#")
-         , ("role", "button"), ("data-toggle", "dropdown")
-         ] name
-      ul_ [("class","dropdown-menu")] $ mapM_ navbarDropdownItem children
-
-navbarDropdownItem :: NavbarDropdownItem site -> WidgetT site IO ()
-navbarDropdownItem item = do
-  render <- getUrlRender
-  case item of
-    NavbarDropdownLink route name -> li_ [] $ anchor route name
-    NavbarDropdownHeader name -> li_ [("class","dropdown-header")] name
-    NavbarDropdownSeparator -> li_ [("class","separator"),("role","divider")] mempty
-
--- Stands for text widget
-tw :: Text -> WidgetT site IO ()
-tw = toWidget . toHtml 
-
-preEscapedWidget :: Text -> WidgetT site IO ()
-preEscapedWidget = toWidget . H.preEscapedToHtml
-
-data CarouselItem site = CarouselItem
-  { ciImage   :: Route site
-  , ciLink    :: Maybe (Route site)
-  , ciCaption :: Maybe (WidgetT site IO ())
-  }
-
-data CarouselIndicators = CarouselIndicatorsOn | CarouselIndicatorsOff
-  deriving (Eq)
-data CarouselControls = CarouselControlsOn | CarouselControlsOff
-  deriving (Eq)
-
--- Carousel Element 
-carousel :: CarouselIndicators -> CarouselControls -> [CarouselItem site] -> WidgetT site IO ()
-carousel indicators controls items = if length items == 0 then mempty else do
-  render <- getUrlRender
-  carouselId <- newIdent
-  div_ [("class","carousel slide"),("data-ride","carousel"),("id",carouselId)] $ do
-    when (indicators == CarouselIndicatorsOn) $ do
-      ol_ [("class","carousel-indicators")] $ do
-        forM_ (zip [0,1..] itemsActive) $ \(i,(active,_)) -> do
-          li_ [ ("data-target", "#" <> carouselId)
-              , ("data-slide-to", Text.pack (show i))
-              , ("class", if active then "active" else "")
-              ] mempty
-    div_ [("class","carousel-inner"), ("role","listbox")] $ do
-      forM_ itemsActive $ \(active,item) -> do
-        div_ [("class","item " <> if active then "active" else "")] $ do
-          wrapWithLink (ciLink item) mempty
-          img_ [("src",render (ciImage item))]
-          for_ (ciCaption item) $ \caption -> do
-            div_ [("class","carousel-caption")] caption
-    when (controls == CarouselControlsOn) $ do
-      a_ [ ("class","left carousel-control")
-         , ("href","#" <> carouselId)
-         , ("role","button")
-         , ("data-slide","prev")
-         ] $ do
-         glyphicon "chevron-left"
-         span_ [("class","sr-only")] "Previous"
-      a_ [ ("class","right carousel-control")
-         , ("href","#" <> carouselId)
-         , ("role","button")
-         , ("data-slide","next")
-         ] $ do
-         glyphicon "chevron-right"
-         span_ [("class","sr-only")] "Next"
-  where 
-  itemsActive = zip (True : repeat False) items
-  wrapWithLink :: Maybe (Route site) -> WidgetT site IO () -> WidgetT site IO ()
-  wrapWithLink mroute w = (\ww -> maybe w ww mroute) $ \route -> do
-    render <- getUrlRender
-    a_ [("href", render route),("style","position:absolute;left:0;right:0;width:100%;height:100%;")] w
-
--- Togglable tabs
-data ToggleTab site = ToggleSection Text (WidgetT site IO ()) | ToggleDropdown Text [(Text,WidgetT site IO ())]
-data ToggleStyle = ToggleStyleTab | ToggleStylePill
-
-togglableTabs :: ToggleStyle -> [ToggleTab site] -> WidgetT site IO ()
-togglableTabs s tabs = do
-  (nav,bodies) <- execWriterT $ forM_ (zip [1..] tabs) $ \(i,tab) -> case tab of
-    ToggleSection title body -> do -- WriterT (Widget,Widget) over a WidgetT
-      theId <- lift newIdent
-      let tabAAttrs = [("role","tab"),("href","#" <> theId),("data-toggle","tab")]
-          tabLiAttrs = (if isFirst then addClass "active" else id) [("role","presentation")]
-          paneClasses = (if isFirst then addClass "active" else id)
-            [("class","tab-pane"),("role","tabpanel"),("id",theId)]
-          isFirst = (i == (1 :: Int))
-      tellFst $ li_ tabLiAttrs $ a_ tabAAttrs $ tw title
-      tellSnd $ div_ paneClasses body
-    _ -> error "figure this out"
-  div_ [] $ do
-    let styleText = case s of
-          ToggleStyleTab -> "nav-tabs"
-          ToggleStylePill -> "nav-pills"
-    ul_ [("class","nav " <> styleText),("role","tablist")] nav
-    div_ [("class","tab-content")] bodies
-  where 
-  tellFst a = tell (a,mempty)
-  tellSnd b = tell (mempty,b)
-  addClass :: Text -> [(Text,Text)] -> [(Text,Text)]
-  addClass klass attrs = case List.lookup "class" attrs of
-    Nothing -> ("class",klass) : attrs
-    Just c -> ("class",c <> " " <> klass) : List.deleteBy ((==) `on` fst) ("class","") attrs
-
-radioButtons :: Context -> Text -> [(Text, WidgetT site IO ())] -> WidgetT site IO ()
-radioButtons ctx name xs = do
-  div_ [("class","btn-group"),("data-toggle","buttons")] $ do
-    forM_ (zip trueThenFalse xs) $ \(isFirst, (theValue,w)) -> do
-      label_ [("class", "btn btn-" <> contextName ctx <> if isFirst then " active" else "")] $ do
-        input_ $ (if isFirst then [("checked","checked")] else [])
-              ++ [("type","radio"),("name",name),("value",theValue),("autocomplete","off")] 
-        " "
-        w
-
-listGroupLinked :: [(Route site,WidgetT site IO ())] -> WidgetT site IO ()
-listGroupLinked items = do
-  render <- getUrlRender
-  div_ [("class","list-group")] $ forM_ items $ \(route,name) -> do
-    a_ [("href",render route),("class","list-group-item")] name
-
-breadcrumbsList :: [(Route site,WidgetT site IO ())] -> WidgetT site IO ()
-breadcrumbsList allCrumbs = case reverse allCrumbs of
-  (_,lastCrumbWidget):crumbs -> ol_ [("class","breadcrumb")] $ do
-    forM_ (reverse crumbs) $ \(route,name) -> li_ [] $ anchor route name
-    li_ [("class","active")] lastCrumbWidget
-  [] -> mempty
-
-popover :: WidgetT site IO () -> WidgetT site IO () -> WidgetT site IO () -> WidgetT site IO ()
-popover title popup inner = do
-  innerId <- newIdent
-  popupWrapId <- newIdent
-  titleWrapId <- newIdent
-  a_ [("href","javascript://"),("id",innerId)] inner
-  div_ [("id",popupWrapId),("style","display:none;")] $ do
-    popup
-  div_ [("id",titleWrapId),("style","display:none;")] $ do
-    title
-  toWidget [julius|
-$().ready(function(){
-  $('##{rawJS innerId}').popover(
-    { html: true
-    , trigger: 'focus'
-    , content: function() { return $('##{rawJS popupWrapId}').html(); }
-    , title: function() { return $('##{rawJS titleWrapId}').html(); }
-    }
-  );
-});
-|]
-
-popoverClickable :: WidgetT site IO () -> WidgetT site IO () -> WidgetT site IO () -> WidgetT site IO ()
-popoverClickable title popup inner = do
-  containerId <- newIdent
-  innerId <- newIdent
-  popupWrapId <- newIdent
-  titleWrapId <- newIdent
-  span_ [("id",containerId)] $ do
-    a_ [("href","javascript://"),("id",innerId)] inner
-    div_ [("id",popupWrapId),("style","display:none;")] $ do
-      popup
-    div_ [("id",titleWrapId),("style","display:none;")] $ do
-      title
-  toWidget [julius|
-$().ready(function(){
-  $('##{rawJS innerId}').popover(
-    { html: true
-    , trigger: 'manual'
-    , content: function() { return $('##{rawJS popupWrapId}').html(); }
-    , title: function() { return $('##{rawJS titleWrapId}').html(); }
-    }
-  );
-  var hidePopover#{rawJS innerId} = function () {
-    $('##{rawJS innerId}').popover('hide');
-    $(document).off("click keypress", hidePopover#{rawJS innerId} );
-  };
-  $('##{rawJS innerId}').focusin(function() {
-      $('##{rawJS innerId}').popover('show');
-    });
-  $('##{rawJS innerId}').on("shown.bs.popover", function() {
-      $('##{rawJS containerId}').find(".popover").on("click keypress", function(e) {
-          e.stopPropagation();
-        });
-      $(document).on("click keypress", hidePopover#{rawJS innerId});
-    });
-});
-|]
-
-trueThenFalse :: [Bool]
-trueThenFalse = True : repeat False
-
diff --git a/src/Yesod/Bootstrap/V3.hs b/src/Yesod/Bootstrap/V3.hs
new file mode 100644
--- /dev/null
+++ b/src/Yesod/Bootstrap/V3.hs
@@ -0,0 +1,175 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE QuasiQuotes #-}
+
+module Yesod.Bootstrap.V3 where
+
+import Yesod.Core
+import Yesod.Elements
+import Text.Blaze (toValue)
+import Data.Text (Text)
+import Data.Monoid
+import Control.Monad
+import Data.Foldable (Foldable(fold))
+import Data.Functor.Identity (Identity(..))
+import Text.Julius (rawJS)
+import qualified Data.List as List
+import qualified Text.Blaze.Html5 as H
+import qualified Text.Blaze.Html5.Attributes as HA
+import qualified Bootstrap.V3 as B
+import qualified Data.Text as Text
+
+container :: Monad m => WidgetT site m a -> WidgetT site m a
+container = div_ [class_ "container"]
+
+row :: Monad m => WidgetT site m a -> WidgetT site m a
+row = div_ [class_ "row"]
+
+column :: Monad m => B.Column -> WidgetT site m a -> WidgetT site m a
+column c = div_ [class_ (toValue (B.columnClass c))]
+
+button :: Monad m => B.Context -> B.Size -> WidgetT site m a -> WidgetT site m a
+button ctx size = button_
+  [ class_ $ toValue $ B.buttonClass ctx size ]
+
+formButtonPost :: B.Context -> B.Size -> Route site -> WidgetT site IO a -> WidgetT site IO a
+formButtonPost = formButton "POST"
+
+formButtonGet :: B.Context -> B.Size -> Route site -> WidgetT site IO a -> WidgetT site IO a
+formButtonGet = formButton "GET"
+
+formButton :: H.AttributeValue -> B.Context -> B.Size -> Route site -> WidgetT site IO a -> WidgetT site IO a
+formButton method ctx size route inner = do
+  urlRender <- getUrlRender
+  form_ [method_ method, action_ (toValue (urlRender route))] $ do
+    button ctx size inner
+
+glyphicon :: Monad m => Text -> WidgetT site m ()
+glyphicon s = span_ [class_ $ toValue $ "glyphicon glyphicon-" <> s] mempty
+
+label :: B.Context -> WidgetT site IO () -> WidgetT site IO ()
+label ctx = span_ [class_ $ toValue $ "label label-" <> B.contextClass ctx]
+
+alert :: B.Context -> WidgetT site IO () -> WidgetT site IO ()
+alert ctx = div_ [class_ $ toValue $ "alert alert-" <> B.contextClass ctx]
+
+alertHtml :: B.Context -> Html -> Html
+alertHtml ctx inner =
+  H.div H.! HA.class_ (toValue $ "alert alert-" <> B.contextClass ctx) $ inner
+
+anchor :: Foldable t => t H.Attribute -> Route site -> WidgetT site IO a -> WidgetT site IO a
+anchor attrs route inner = do
+  urlRender <- getUrlRender
+  a_ (Identity $ (href_ $ toValue $ urlRender route) <> fold attrs) inner
+
+anchorButton :: Foldable t => B.Context -> B.Size -> t H.Attribute -> Route site -> WidgetT site IO () -> WidgetT site IO ()
+anchorButton ctx size attrs = anchor
+  (Identity $ (class_ $ toValue $ B.buttonClass ctx size) <> fold attrs)
+
+navbar ::
+     B.NavbarTheme
+  -> B.NavbarPosition
+  -> Route site
+  -> WidgetT site IO ()
+  -> [B.NavbarItem (Route site) (WidgetT site IO ())]
+  -> [B.NavbarItem (Route site) (WidgetT site IO ())]
+  -> WidgetT site IO ()
+navbar theme pos headerRoute headerContent items rightItems = do
+  navbarId <- newIdent
+  render <- getUrlRender
+  nav_ [class_ $ toValue $ Text.concat
+         [ "navbar "
+         , B.navbarThemeClass theme
+         , " "
+         , B.navbarPositionClass pos
+         ]
+       ] $ do
+    div_ [class_ containerClass] $ do
+      div_ [class_ "navbar-header"] $ do
+        button_ [ class_ "navbar-toggle collapsed"
+                , type_ "button"
+                , H.dataAttribute "toggle" "collapse"
+                , H.dataAttribute "target" (toValue $ "#" <> navbarId)
+                , H.customAttribute "aria-expanded" "false"
+                , H.customAttribute "aria-controls" (toValue navbarId)
+                ] $ do
+          span_ [class_ "sr-only"] "Toggle Navigation"
+          replicateM_ 3 $ span_ [class_ "icon-bar"] mempty
+        a_ [href_ $ toValue $ render headerRoute, class_ "navbar-brand"] headerContent
+      div_ [class_ "navbar-collapse collapse", id_ $ toValue navbarId] $ do
+        ul_ [class_ "nav navbar-nav"] $ mapM_ navbarItem items
+        ul_ [class_ "nav navbar-nav navbar-right"] $ mapM_ navbarItem rightItems
+  where
+  containerClass = case pos of
+    B.NavbarPositionStandard -> "container-fluid"
+    B.NavbarPositionStatic -> "container"
+    B.NavbarPositionFixed -> "container"
+
+navbarItem :: B.NavbarItem (Route site) (WidgetT site IO ()) -> WidgetT site IO ()
+navbarItem item = do
+  render <- getUrlRender
+  li_ [] $ case item of
+    B.NavbarItemLink route name -> anchor [] route name
+    B.NavbarItemDropdown name children -> do
+      a_ [ class_ "dropdown-toggle"
+         , href_ "#"
+         , H.customAttribute "role" "button"
+         , H.dataAttribute "toggle" "dropdown"
+         ] name
+      ul_ [class_ "dropdown-menu"] $ mapM_ navbarDropdownItem children
+
+navbarDropdownItem :: B.NavbarDropdownItem (Route site) (WidgetT site IO ()) -> WidgetT site IO ()
+navbarDropdownItem item = do
+  render <- getUrlRender
+  case item of
+    B.NavbarDropdownItemLink route name -> li_ [] $ anchor [] route name
+    B.NavbarDropdownItemHeader name -> li_ [class_ "dropdown-header"] name
+    B.NavbarDropdownItemSeparator -> li_ [class_ "separator", H.customAttribute "role" "divider"] mempty
+
+breadcrumbsList :: [(Route site,WidgetT site IO ())] -> WidgetT site IO ()
+breadcrumbsList allCrumbs = case List.reverse allCrumbs of
+  (_,lastCrumbWidget):crumbs -> ol_ [class_ "breadcrumb"] $ do
+    forM_ (List.reverse crumbs) $ \(route,name) -> li_ [] $ anchor [] route name
+    li_ [class_ "active"] lastCrumbWidget
+  [] -> mempty
+
+popoverClickable ::
+     WidgetT site IO () -- ^ Title
+  -> WidgetT site IO () -- ^ Popup
+  -> WidgetT site IO () -- ^ Inner Content
+  -> WidgetT site IO ()
+popoverClickable title popup inner = do
+  containerId <- newIdent
+  innerId <- newIdent
+  popupWrapId <- newIdent
+  titleWrapId <- newIdent
+  span_ [id_ $ toValue containerId] $ do
+    a_ [href_ "javascript://", id_ $ toValue innerId] inner
+    div_ [id_ $ toValue popupWrapId, style_' "display:none;"] $ do
+      popup
+    div_ [id_ $ toValue titleWrapId, style_' "display:none;"] $ do
+      title
+  toWidget [julius|
+$().ready(function(){
+  $('##{rawJS innerId}').popover(
+    { html: true
+    , trigger: 'manual'
+    , content: function() { return $('##{rawJS popupWrapId}').html(); }
+    , title: function() { return $('##{rawJS titleWrapId}').html(); }
+    }
+  );
+  var hidePopover#{rawJS innerId} = function () {
+    $('##{rawJS innerId}').popover('hide');
+    $(document).off("click keypress", hidePopover#{rawJS innerId} );
+  };
+  $('##{rawJS innerId}').focusin(function() {
+      $('##{rawJS innerId}').popover('show');
+    });
+  $('##{rawJS innerId}').on("shown.bs.popover", function() {
+      $('##{rawJS containerId}').find(".popover").on("click keypress", function(e) {
+          e.stopPropagation();
+        });
+      $(document).on("click keypress", hidePopover#{rawJS innerId});
+    });
+});
+|]
diff --git a/src/Yesod/Form/Generic.hs b/src/Yesod/Form/Generic.hs
deleted file mode 100644
--- a/src/Yesod/Form/Generic.hs
+++ /dev/null
@@ -1,90 +0,0 @@
-module Yesod.Form.Generic where
-
-import Yesod.Core
-import Yesod.Form
-import Data.Text (Text)
-import Control.Monad
-import Control.Applicative
-import Data.Monoid
-import Control.Monad.Trans.RWS (ask, get, put, runRWST, tell, evalRWST, local)
-import Data.Maybe
-import qualified Data.Map as Map
-
-newtype GForm w m a = GForm 
-  { unGForm :: (HandlerSite m, [Text])
-            -> Maybe (Env, FileEnv)
-            -> Ints
-            -> m (FormResult a, w, Ints, Enctype)
-  }
-
-instance Monad m => Functor (GForm w m) where
-  fmap f (GForm a) = GForm $ \x y z -> liftM go $ a x y z
-    where go (w, x, y, z) = (fmap f w, x, y, z)
-
-instance (Monad m, Monoid w) => Applicative (GForm w m) where
-  pure x = GForm $ const $ const $ \ints -> return (FormSuccess x, mempty, ints, mempty)
-  (GForm f) <*> (GForm g) = GForm $ \mr env ints -> do
-    (a, b, ints', c) <- f mr env ints
-    (x, y, ints'', z) <- g mr env ints'
-    return (a <*> x, b <> y, ints'', c <> z)
-
-instance Monoid w => MonadTrans (GForm w) where
-  lift f = GForm $ \_ _ ints -> do
-    x <- f
-    return (FormSuccess x, mempty, ints, mempty)
-
-mghelper :: MonadHandler m
-         => Enctype 
-         -> ([Text] -> [FileInfo] -> m (FormResult a)) -- ^ parser
-         -> (Text -> [Text] -> FormResult a -> w) -- ^ function for building output, needs name and vals
-         -> MForm m (FormResult a, w)
-mghelper enctype parse buildOutput = do
-  tell enctype
-  mp <- askParams
-  name <- newFormIdent 
-  case mp of
-    Nothing -> return (FormMissing, buildOutput name [] FormMissing)
-    Just p -> do
-      mfs <- askFiles
-      let mvals = fromMaybe [] $ Map.lookup name p
-          files = fromMaybe [] $ mfs >>= Map.lookup name
-      res <- lift $ parse mvals files
-      return (res, buildOutput name mvals res)
-
-ghelper :: MonadHandler m
-        => Enctype 
-        -> ([Text] -> [FileInfo] -> m (FormResult a)) -- ^ parser
-        -> (Text -> [Text] -> FormResult a -> w) -- ^ function for building output, needs name
-        -> GForm w m a
-ghelper a b c = formToGForm (mghelper a b c)
-
-formToGForm :: (HandlerSite m ~ site, Monad m)
-            => MForm m (FormResult a, w)
-            -> GForm w m a
-formToGForm form = GForm $ \(site, langs) env ints -> do
-  ((a, w), ints', enc) <- runRWST form (env, site, langs) ints
-  return (a, w, ints', enc)
-
-gFormToForm :: (Monad m, HandlerSite m ~ site)
-            => GForm w m a
-            -> MForm m (FormResult a, w)
-gFormToForm (GForm gform) = do
-  ints <- get
-  (env, site, langs) <- ask
-  (a, w, ints', enc) <- lift $ gform (site, langs) env ints
-  put ints'
-  tell enc
-  return (a, w)
-
-gFormToFormCsrf :: (Monad m, HandlerSite m ~ site)
-                => GForm (WidgetT site IO ()) m a
-                -> Html
-                -> MForm m (FormResult a, (WidgetT site IO ()))
-gFormToFormCsrf g h = do
-  (r,w) <- gFormToForm g
-  return (r,toWidget h <> w)
-
-monoidToGForm :: Monad m => w -> GForm w m ()
-monoidToGForm w = formToGForm $ return (FormSuccess (), w)
-
-
diff --git a/src/Yesod/Form/Generic/Bootstrap.hs b/src/Yesod/Form/Generic/Bootstrap.hs
deleted file mode 100644
--- a/src/Yesod/Form/Generic/Bootstrap.hs
+++ /dev/null
@@ -1,540 +0,0 @@
-module Yesod.Form.Generic.Bootstrap where
-
-import Yesod.Form
-import Yesod.Form.Generic
-import Yesod.Core
-import Yesod.Core.Widget
-import Data.Text (Text)
-import qualified Data.Text as Text
-import qualified Data.Text.Encoding as Text
-import qualified Text.Email.Validate as Email
-import qualified Data.Yaml as Yaml
-import Text.Shakespeare.I18N (RenderMessage)
-import Yesod.Bootstrap
-import Data.Maybe
-import Text.Read (readMaybe)
-import Control.Applicative
-import Control.Monad
-import Data.Time (Day)
-import Data.Monoid
-import Lens.Family
-import Lens.Family2.TH
-import Text.Julius (rawJS)
-import Debug.Trace
-import Data.Either.Combinators
-import Data.String
-import Control.Monad.Random
-import Database.Persist (PersistField)
-import Database.Persist.Sql (PersistFieldSql)
-import Yesod.Markdown
-import Data.Conduit
-import Data.Conduit.Lazy (lazyConsume)
-import qualified Data.Conduit.Text as Conduit
-import Text.Blaze.Html (preEscapedToHtml)
-import Yesod.Form.Generic.Bootstrap.Internal 
-
-class YesodMarkdownRender site where
-  markdownRenderSubsite :: Route MarkdownRender -> Route site
-
-instance YesodSubDispatch MarkdownRender (HandlerT master IO) where
-  yesodSubDispatch = $(mkYesodSubDispatch resourcesMarkdownRender)
-
-getMarkdownRender :: a -> MarkdownRender
-getMarkdownRender = const MarkdownRender
-
-postMarkdownRenderR :: HandlerT MarkdownRender (HandlerT site IO) Html
-postMarkdownRenderR = do
-  ts <- lazyConsume $ rawRequestBody =$= Conduit.decode Conduit.utf8
-  let mkd = Markdown $ Text.concat ts
-  return $ markdownToHtmlCustom mkd
-
-markdownToHtmlCustom :: Markdown -> Html
-markdownToHtmlCustom m@(Markdown t)
-  | m == mempty = preEscapedToHtml ("<span class=\"text-muted\">Preview</span>" :: Text)
-  | otherwise   = case markdownToHtml (Markdown (Text.filter (/= '\r') t)) of
-      Left _ -> preEscapedToHtml ("<span class=\"text-muted\">Could not render</span>" :: Text)
-      Right a -> a
-
-data FieldConfig m a = FieldConfig
-  { _fcLabel :: Maybe (WidgetT (HandlerSite m) IO ())
-  , _fcPlaceholder :: Maybe (SomeMessage (HandlerSite m))
-  , _fcTooltip :: Maybe (SomeMessage (HandlerSite m))
-  , _fcId :: Maybe Text
-  , _fcName :: Maybe Text
-  , _fcValue :: Maybe a
-  , _fcReadonly :: Bool
-  , _fcValidate :: a -> m (Either (SomeMessage (HandlerSite m)) a)
-  }
-makeLenses ''FieldConfig
-
-instance Monad m => Monoid (FieldConfig m a) where
-  mempty = FieldConfig Nothing Nothing Nothing Nothing Nothing Nothing False (return . Right)
-  FieldConfig a1 b1 c1 d1 e1 f1 r1 v1 `mappend` FieldConfig a2 b2 c2 d2 e2 f2 r2 v2 = 
-    FieldConfig (a2 <|> a1) (b2 <|> b1) (c2 <|> c1) (d2 <|> d1) (e2 <|> e1) (f2 <|> f1) (r1 || r2) 
-    $ \a -> do
-      e <- v1 a
-      case e of 
-        Left err -> return $ Left err
-        Right a' -> return $ Right a'
-
-instance Monad m => IsString (FieldConfig m a) where
-  fromString s = mempty {_fcLabel = Just (toWidget (toHtml s))}
-
-render :: Monad m => GForm (WidgetT site IO ()) m a -> Html -> MForm m (FormResult a, WidgetT site IO ())
-render g h = gFormToForm (monoidToGForm (toWidget h) *> g)
-
-greenOnSuccess :: Bool
-greenOnSuccess = False
-
-simple :: (MonadHandler m, HandlerSite m ~ site, RenderMessage site FormMessage)
-  => Text -- ^ input type
-  -> ([Text] -> [FileInfo] -> m (FormResult a))
-  -> (a -> Text)
-  -> FieldConfig m a -> GForm (WidgetT site IO ()) m a
-simple typ parser display config = ghelper UrlEncoded (fullValidate parser (_fcValidate config)) $ \name vals res -> 
-  let baseInput = labelAndInput (fromMaybe mempty $ _fcLabel config) name typ (_fcReadonly config)
-  in case res of
-    FormMissing -> formGroup $ baseInput $ maybe "" display (_fcValue config)
-    FormSuccess a -> (if greenOnSuccess then formGroupFeedback Success else formGroup) $ do
-      baseInput (display a)
-    FormFailure errs -> formGroupFeedback Error $ do
-      baseInput $ fromMaybe "" $ listToMaybe vals
-      glyphiconFeedback "remove"
-      helpBlock $ ul_ [("class","list-unstyled")] $ mapM_ (li_ [] . tw) errs
-
-class YesodTypeahead site where
-  routeTypeaheadJs :: site -> Route site
-  routeTypeaheadCss :: site -> Route site
-
--- The result from the route is expected to be a JSON array. Also, the route
--- is expected to respond to a POST request with the body as the text we are
--- searching for.
-typeahead :: (YesodTypeahead site, MonadHandler m, HandlerSite m ~ site, RenderMessage site FormMessage)
-  => Route site -> FieldConfig m Text -> GForm (WidgetT site IO ()) m Text
-typeahead route config = ghelper UrlEncoded (fullValidate parser (_fcValidate config)) $ \name vals res -> do
-  inputId <- newIdent
-  let baseAttrs = [("id",inputId),("class","form-control"),("name",name),("type","text")]
-      addReadonly = if _fcReadonly config then (("readonly","readonly"):) else id
-      attrs = addReadonly baseAttrs
-      baseInput t = do
-        whenMaybe (_fcLabel config) controlLabel
-        input_ attrs
-  yesod <- getYesod
-  addStylesheet $ routeTypeaheadCss yesod
-  addScript $ routeTypeaheadJs yesod
-  typeaheadJs route inputId 
-  case res of
-    FormMissing -> formGroup $ baseInput $ maybe "" display (_fcValue config)
-    FormSuccess a -> (if greenOnSuccess then formGroupFeedback Success else formGroup) $ do
-      baseInput (display a)
-    FormFailure errs -> formGroupFeedback Error $ do
-      baseInput $ fromMaybe "" $ listToMaybe vals
-      glyphiconFeedback "remove"
-      helpBlock $ ul_ [("class","list-unstyled")] $ mapM_ (li_ [] . tw) errs
-  where parser = (gparseHelper (return . Right) Nothing)
-        display = id
-
-typeaheadJs :: Route site -> Text -> WidgetT site IO ()
-typeaheadJs route inputId = toWidget [julius|
-$().ready(function(){
-  var serNum = $('##{rawJS inputId}');
-  serNum.typeahead({
-    source: function (query, process) {
-      return $.post('@{route}', query, function(data){
-        return process(data);
-      });
-    },
-    items: 'all',
-    minLength: 2,
-    afterSelect: function(ser) { 
-      // serNum.closest('form').submit();
-    }
-  });     
-});
-|]
-
-simpleCheck :: (MonadHandler m, HandlerSite m ~ site, RenderMessage site FormMessage)
-  => Text -- ^ input type
-  -> ([Text] -> [FileInfo] -> m (FormResult (Maybe a)))
-  -> (Maybe a -> Text)
-  -> FieldConfig m (Maybe a) -> GForm (WidgetT site IO ()) m (Maybe a)
-simpleCheck typ parser display config = formToGForm $ do
-  (checkId, inputId) <- (,) <$> newIdent <*> newIdent
-  (checkRes, checkWidget) <- mghelper UrlEncoded (fullValidate (gparseHelper (return . checkBoxParser) (Just False)) (return . Right)) $ \name _vals res -> do
-    val <- decipherCheckRes res
-    input_ $ boolAttrs [("checked",val)] ++ [("id",checkId),("name",name),("value","yes"),("type","checkbox")]
-  (inputRes, inputWidget) <- mghelper UrlEncoded (fullValidate parser (_fcValidate config)) $ \name vals res -> do
-    isChecked <- decipherCheckRes checkRes
-    let baseInputGroup val = inputGroup $ do
-          inputGroupAddon checkWidget
-          input_ $ boolAttrs [("readonly", not isChecked)] ++ 
-            [("id",inputId),("class","form-control"),("type",typ),("name",name),("value",val)]
-    case (isChecked,res) of
-      (_, FormMissing) -> formGroup $ do
-        maybe mempty controlLabel (_fcLabel config)
-        baseInputGroup $ maybe "" display (_fcValue config)
-      (_, FormSuccess a) -> (if greenOnSuccess then formGroupFeedback Success else formGroup) $ do
-        maybe mempty controlLabel (_fcLabel config)
-        baseInputGroup (display a)
-      (False,FormFailure errs) -> (if greenOnSuccess then formGroupFeedback Success else formGroup) $ do
-        maybe mempty controlLabel (_fcLabel config)
-        baseInputGroup ""
-      (True,FormFailure errs) -> formGroupFeedback Error $ do
-        maybe mempty controlLabel (_fcLabel config)
-        baseInputGroup $ fromMaybe "" $ listToMaybe vals
-        glyphiconFeedback "remove"
-        helpBlock $ ul_ [("class","list-unstyled")] $ mapM_ (li_ [] . tw) errs
-  return ( checkRes `bindFormResult` \b -> if traceShowId b then inputRes else pure Nothing
-         , inputWidget <> simpleCheckJs checkId inputId )
-  where decipherCheckRes r = case r of
-          FormSuccess b -> return b
-          FormFailure _ -> permissionDenied "Bootstrap checkbox field somehow failed" 
-          FormMissing   -> return $ isJust $ join (_fcValue config)
-
-select :: (RenderMessage site FormMessage, Eq a)
-  => HandlerT site IO (OptionList a) 
-  -> FieldConfig (HandlerT site IO) a 
-  -> GForm (WidgetT site IO ()) (HandlerT site IO) a
-select opts c = ghelper UrlEncoded 
-  (fieldParseToGParse parse) $ \name vals res -> do
-    theId <- newIdent 
-    let r = case res of
-              FormSuccess a -> Right a
-              FormMissing -> case _fcValue c of
-                Nothing -> Left ""
-                Just a -> Right a
-              FormFailure _ -> Left ""
-    formGroup $ do
-      whenMaybe (_fcLabel c) controlLabel
-      view theId name [("class","form-control")] r True
-  where Field parse view enctype = selectField opts
-
-newtype UploadFilename = UploadFilename { getUploadFilename :: Text }
-  deriving (PersistField, PersistFieldSql, Show, Read)
-
-class YesodUpload site where
-  uploadDirectory :: site -> String
-  uploadRoute :: UploadFilename -> Route site
-
-yaml :: (FromJSON a, ToJSON a, HandlerSite m ~ site, MonadHandler m, RenderMessage site FormMessage) 
-  => a -> FieldConfig m a -> GForm (WidgetT site IO ()) m a
-yaml example c = ghelper UrlEncoded (fullValidate (gparseHelper (return . mapLeft (SomeMessage . Text.pack) . Yaml.decodeEither . Text.encodeUtf8) Nothing) (_fcValidate c))
-  $ \name vals res -> do
-    preId    <- newIdent
-    buttonId <- newIdent
-    yamlJs preId buttonId
-    let thePre = pre_ [("id",preId),("style","display:none")] $ tw $ yamlEncodeText example
-        baseAttrs = [("class","form-control"),("name",name),("rows","5")]
-        addReadonly = if (_fcReadonly c) then (("readonly","readonly"):) else id
-        attrs = addReadonly baseAttrs
-        baseInput t = do
-          whenMaybe (_fcLabel c) controlLabel
-          textarea_ attrs (tw t)
-    case res of
-      FormMissing -> formGroup $ do
-        baseInput $ maybe "" yamlEncodeText (_fcValue c)
-        button_ [("class","btn btn-link"),("id",buttonId),("type","button")] $ tw "Show Example"
-        thePre
-      FormSuccess a -> (if greenOnSuccess then formGroupFeedback Success else formGroup) $ do
-        baseInput (yamlEncodeText a)
-        button_ [("class","btn btn-link"),("id",buttonId),("type","button")] $ tw "Show Example"
-        thePre
-      FormFailure errs -> formGroupFeedback Error $ do
-        baseInput $ fromMaybe "" $ listToMaybe vals
-        glyphiconFeedback "remove"
-        helpBlock $ ul_ [("class","list-unstyled")] $ mapM_ (li_ [] . tw) errs
-        button_ [("class","btn btn-link"),("id",buttonId),("type","button")] $ tw "Show Example"
-        thePre
-  where yamlEncodeText = Text.decodeUtf8 . Yaml.encode
-  
-yamlJs :: Text -> Text -> WidgetT site IO ()
-yamlJs preId buttonId = toWidget [julius|
-$().ready(function(){
-  var showing = false;
-  var button = $('##{rawJS buttonId}');
-  var pre = $('##{rawJS preId}');
-  button.click(function(){
-    showing = !showing;
-    pre.slideToggle();
-    if(showing)
-      button.text("Hide Example");
-    else
-      button.text("Show Example");
-  });
-});
-|]
-
-markdown :: (YesodMarkdownRender site, MonadHandler m, HandlerSite m ~ site, RenderMessage site FormMessage)
-  => FieldConfig m Markdown -> GForm (WidgetT site IO ()) m Markdown
-markdown c = ghelper UrlEncoded (fullValidate (gparseHelper (return . Right . Markdown . Text.filter (/= '\r')) Nothing) (_fcValidate c)) 
-  $ \name vals res -> do
-    wellId <- newIdent
-    inputId <- newIdent
-    render <- getUrlRender
-    markdownJs wellId inputId (render $ markdownRenderSubsite MarkdownRenderR)
-    let theWell = helpBlock . div_ [("class","well well-sm"),("id",wellId)] . toWidget
-        baseAttrs = [("class","form-control"),("name",name),("rows","5"),("id",inputId)]
-        addReadonly = if (_fcReadonly c) then (("readonly","readonly"):) else id
-        attrs = addReadonly baseAttrs
-        baseInput t = do
-          whenMaybe (_fcLabel c) controlLabel
-          textarea_ attrs (tw t)
-    case res of
-      FormMissing -> formGroup $ do
-        baseInput $ maybe "" unMarkdown (_fcValue c)
-        theWell $ markdownToHtmlCustom $ fromMaybe mempty (_fcValue c)
-      FormSuccess a -> (if greenOnSuccess then formGroupFeedback Success else formGroup) $ do
-        baseInput (unMarkdown a)
-        theWell $ markdownToHtmlCustom a
-      FormFailure errs -> formGroupFeedback Error $ do
-        baseInput $ fromMaybe "" $ listToMaybe vals
-        glyphiconFeedback "remove"
-        theWell $ markdownToHtmlCustom mempty
-        helpBlock $ ul_ [("class","list-unstyled")] $ mapM_ (li_ [] . tw) errs
-
-markdownJs :: Text -> Text -> Text -> WidgetT site IO ()
-markdownJs wellId inputId url = toWidget [julius|
-$().ready(function(){
-  var hasChanged = false;
-  var input = $('##{rawJS inputId}');
-  var well = $('##{rawJS wellId}');
-  var runUpdate = function(){
-    if(!hasChanged) return;
-    $.ajax({ type: "POST"
-           , url: "#{rawJS url}"
-           , data: input.val()
-           , dataType: 'html'
-           , success: function(data) {
-               well.html(data);
-               hasChanged = false;
-             } 
-           });
-  };
-  setInterval(runUpdate, 1000);
-  input.on('input',function(){
-    hasChanged = true;
-  });
-});
-|]
-
-file :: (YesodUpload site, MonadHandler m, HandlerSite m ~ site, RenderMessage site FormMessage)
-  => FieldConfig m UploadFilename -> GForm (WidgetT site IO ()) m UploadFilename
-file c = ghelper Multipart
-  (fullValidate (fileParseHelper (_fcValue c)) (_fcValidate c)) $ \name _vals res -> do
-    formGroup $ do
-      whenMaybe (_fcLabel c) controlLabel
-      input_ [("type","file"),("name",name)] 
-      case res of
-        FormFailure errs -> helpBlock $ ul_ [("class","list-unstyled")] $ mapM_ (li_ [] . tw) errs
-        _ -> mempty
-      whenMaybe (_fcValue c) $ \filename -> do
-        render <- getUrlRender
-        helpBlock $ img_ [("width","140"),("src",render $ uploadRoute filename),("class","img-thumbnail")]
-    
-  
-fileParseHelper :: (YesodUpload site, MonadHandler m, HandlerSite m ~ site, RenderMessage site FormMessage)
-  => (Maybe UploadFilename) -- ^ If this is Just, then the field is not required.
-  -> [Text] -> [FileInfo] -> m (FormResult UploadFilename)
-fileParseHelper mdef _ [] = return $ case mdef of
-  Nothing -> FormMissing
-  Just a -> FormSuccess a
-fileParseHelper _ _ (x:_) = do
-  app <- getYesod
-  name <- liftIO $ moveIt (uploadDirectory app) x
-  return (FormSuccess name)
-
-moveIt :: String -> FileInfo -> IO UploadFilename
-moveIt dir fi = do
-  baseFilename <- randomUpperConsonantText 24
-  let ext = snd $ Text.breakOn "." (fileName fi)
-      fullFileName = baseFilename <> ext
-  fileMove fi $ Text.unpack $ mempty 
-    <> Text.pack dir 
-    <> "/" 
-    <> fullFileName
-  return $ UploadFilename fullFileName
-
-randomUpperConsonantText :: Int -> IO Text
-randomUpperConsonantText n = id
-  $ fmap Text.pack 
-  $ evalRandIO 
-  $ replicateM n
-  $ uniform allConsonants
-  where allConsonants = filter (not . isVowel) ['A'..'Z']
-
-isVowel :: Char -> Bool
-isVowel c = case c of
-  'a' -> True
-  'e' -> True
-  'i' -> True
-  'o' -> True
-  'u' -> True
-  'A' -> True
-  'E' -> True
-  'I' -> True
-  'O' -> True
-  'U' -> True
-  _   -> False
-
-simpleCheckJs :: Text -> Text -> WidgetT site IO ()
-simpleCheckJs checkId inputId = toWidget [julius|
-$().ready(function(){
-  $('##{rawJS checkId}').change(function(){
-    var enabled = this.checked;
-    var input = $('##{rawJS inputId}');
-    if (!enabled) input.val("");
-    input.prop('readonly',!enabled);
-  });
-});
-|]
-
-bindFormResult :: FormResult a -> (a -> FormResult b) -> FormResult b
-bindFormResult ra f = case ra of
-  FormFailure errs -> FormFailure errs
-  FormMissing -> FormMissing
-  FormSuccess a -> f a
-
-ifA :: Applicative f => f Bool -> f a -> f a -> f a
-ifA t c a = g <$> t <*> c <*> a where g b x y = if b then x else y
-
-boolAttrs :: [(Text,Bool)] -> [(Text,Text)]
-boolAttrs = map (\t -> (fst t, fst t)) . filter snd
-
-labelAndInput :: WidgetT site IO () -> Text -> Text -> Bool -> Text -> WidgetT site IO ()
-labelAndInput labelWidget name typ readonly val = do
-  let baseAttrs = [("class","form-control"),("type",typ),("name",name),("value",val)]
-      addReadonly = if readonly then (("readonly","readonly"):) else id
-  controlLabel labelWidget
-  input_ (addReadonly $ baseAttrs)
-
-fieldParseToGParse :: (MonadHandler m)
-  => ([Text] -> [FileInfo] -> m (Either (SomeMessage (HandlerSite m)) (Maybe a)))
-  -> [Text] -> [FileInfo] -> m (FormResult a)
-fieldParseToGParse parse ts fs = do
-  e <- parse ts fs 
-  case e of
-    Left msg -> do 
-      langs <- languages
-      site  <- getYesod
-      return $ FormFailure [renderMessage site langs msg]
-    Right Nothing -> return FormMissing
-    Right (Just a) -> return (FormSuccess a)
-
-fullValidate :: MonadHandler m 
-  => ([Text] -> [FileInfo] -> m (FormResult a)) 
-  -> (a -> m (Either (SomeMessage (HandlerSite m)) a))
-  -> [Text] -> [FileInfo] -> m (FormResult a)
-fullValidate parser validate ts fs = do
-  res <- parser ts fs 
-  case res of
-    FormSuccess a -> do
-      e <- validate a
-      case e of
-        Left msg -> do
-          langs <- languages
-          site  <- getYesod
-          return $ FormFailure [renderMessage site langs msg]
-        Right b -> return $ FormSuccess b
-    _ -> return res
-
-text :: (MonadHandler m, HandlerSite m ~ site, RenderMessage site FormMessage)
-  => FieldConfig m Text -> GForm (WidgetT site IO ()) m Text
-text = simple "text" 
-  (gparseHelper (return . Right) Nothing) id
-
-textOpt :: (MonadHandler m, HandlerSite m ~ site, RenderMessage site FormMessage)
-  => FieldConfig m (Maybe Text) -> GForm (WidgetT site IO ()) m (Maybe Text)
-textOpt = simple "text" (gparseHelper (return . Right . Just) (Just Nothing)) (fromMaybe "")
-
-textCheck :: (MonadHandler m, HandlerSite m ~ site, RenderMessage site FormMessage)
-  => FieldConfig m (Maybe Text) -> GForm (WidgetT site IO ()) m (Maybe Text)
-textCheck = simpleCheck "text" 
-  (gparseHelper (return . Right . Just) Nothing) 
-  (fromMaybe "")
-
-int :: (MonadHandler m, HandlerSite m ~ site, RenderMessage site FormMessage)
-  => FieldConfig m Int -> GForm (WidgetT site IO ()) m Int
-int = simple "number" (gparseHelper (return . parseInt) Nothing) (Text.pack . show)
-
-intCheck :: (MonadHandler m, HandlerSite m ~ site, RenderMessage site FormMessage)
-  => FieldConfig m (Maybe Int) -> GForm (WidgetT site IO ()) m (Maybe Int)
-intCheck = simpleCheck "number" 
-  (gparseHelper (return . fmap Just . parseInt) Nothing) 
-  (maybe "" (Text.pack . show))
-
-day :: (MonadHandler m, HandlerSite m ~ site, RenderMessage site FormMessage)
-  => FieldConfig m Day -> GForm (WidgetT site IO ()) m Day
-day = simple "date" 
-  (gparseHelper (return . mapLeft SomeMessage . parseDate . Text.unpack) Nothing) 
-  (Text.pack . show)
-
-dayCheck :: (MonadHandler m, HandlerSite m ~ site, RenderMessage site FormMessage)
-  => FieldConfig m (Maybe Day) -> GForm (WidgetT site IO ()) m (Maybe Day)
-dayCheck = simpleCheck "date" 
-  (gparseHelper (return . fmap Just . mapLeft SomeMessage . parseDate . Text.unpack) Nothing)
-  (maybe "" (Text.pack . show))
--- 
--- email :: (MonadHandler m, HandlerSite m ~ site, RenderMessage site FormMessage)
---   => WidgetT site IO () -> Maybe Text -> GForm (WidgetT site IO ()) m Text
--- email = simple "email" (gparseHelper textEmailValidate Nothing) id
--- 
-bool :: (MonadHandler m, HandlerSite m ~ site, RenderMessage site FormMessage)
-  => FieldConfig m Bool -> GForm (WidgetT site IO ()) m Bool
-bool config = ghelper UrlEncoded (fullValidate (gparseHelper (return . checkBoxParser) (Just False)) (_fcValidate config)) $ \name _vals res -> do
-  val <- case res of
-    FormSuccess b -> return b
-    FormFailure _ -> permissionDenied "Bootstrap checkbox field somehow failed" -- should be impossible
-    FormMissing   -> return $ fromMaybe False (_fcValue config)
-  let applyVal = if val then (("checked","checked"):) else id
-  checkbox $ label_ [] $ do 
-    input_ $ applyVal [("name",name),("value","yes"),("type","checkbox")]
-    fromMaybe mempty $ _fcLabel config
-
-checkBoxParser :: Text -> Either (SomeMessage site) Bool
-checkBoxParser x = case x of
-  "yes" -> Right True 
-  "on"  -> Right True
-  _     -> Right False
-
-textEmailValidate :: Text -> Either FormMessage Text
-textEmailValidate t = if Email.isValid (Text.encodeUtf8 t)
-  then Right t
-  else Left (MsgInvalidEmail t)
-
-submit :: Monad m => Context -> Text -> GForm (WidgetT site IO ()) m ()
-submit ctx t = monoidToGForm $ button_ [("type","submit"),("class","btn btn-" <> contextName ctx)] $ tw t
-
-parseInt :: RenderMessage site FormMessage => Text -> Either (SomeMessage site) Int
-parseInt t = case readMaybe (Text.unpack t) of
-  Nothing -> Left (SomeMessage (MsgInvalidInteger t))
-  Just n -> Right n
-  
--- specialRight :: a -> Either Text a 
--- specialRight = Right
-
-gparseHelper :: (MonadHandler m, HandlerSite m ~ site, RenderMessage site FormMessage)
-             => (Text -> m (Either (SomeMessage site) a))
-             -> (Maybe a) -- ^ If this is Just, then the field is not required.
-             -> [Text] -> [FileInfo] -> m (FormResult a)
-gparseHelper _ mdef [] _ = return $ case mdef of
-  Nothing -> FormMissing
-  Just a -> FormSuccess a
-gparseHelper _ mdef ("":_) _ = case mdef of
-  Nothing -> do
-    langs <- languages
-    site <- getYesod
-    return $ FormFailure [renderMessage site langs MsgValueRequired]
-  Just a -> return (FormSuccess a)
-gparseHelper f _ (x:_) _  = do
-  e <- f x
-  case e of
-    Left msg -> do
-      langs <- languages
-      site <- getYesod
-      return $ FormFailure [renderMessage site langs msg]
-    Right a -> return (FormSuccess a)
-
-whenMaybe :: Applicative m => Maybe a -> (a -> m ()) -> m ()
-whenMaybe Nothing _ = pure ()
-whenMaybe (Just a) f = f a
-
diff --git a/src/Yesod/Form/Generic/Bootstrap/Internal.hs b/src/Yesod/Form/Generic/Bootstrap/Internal.hs
deleted file mode 100644
--- a/src/Yesod/Form/Generic/Bootstrap/Internal.hs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Yesod.Form.Generic.Bootstrap.Internal where
-
-import Yesod.Core
-
-data MarkdownRender = MarkdownRender
-mkYesodSubData "MarkdownRender" [parseRoutes|
-/markdown/render MarkdownRenderR POST
-|]
-
diff --git a/yesod-bootstrap.cabal b/yesod-bootstrap.cabal
--- a/yesod-bootstrap.cabal
+++ b/yesod-bootstrap.cabal
@@ -1,53 +1,29 @@
--- Initial yesod-bootstrap.cabal generated by cabal init.  For further 
--- documentation, see http://haskell.org/cabal/users-guide/
-
 name:                yesod-bootstrap
-version:             0.3
+version:             0.4
 synopsis:            Bootstrap widgets for yesod
--- description:         
+description:         Lots of bootstrap widgets for yesod
 license:             MIT
 license-file:        LICENSE
+homepage:            https://github.com/andrewthad/haskell-bootstrap
 author:              Andrew Martin
 maintainer:          andrew.thaddeus@gmail.com
--- copyright:           
+copyright:           Andrew Martin 2016
 category:            Web
 build-type:          Simple
--- extra-source-files:  
 cabal-version:       >=1.10
 
 library
-  exposed-modules:     Yesod.Bootstrap
-                     , Yesod.Form.Generic
-                     , Yesod.Form.Generic.Bootstrap
-                     , Yesod.Form.Generic.Bootstrap.Internal
-  default-extensions:  QuasiQuotes
-                     , GeneralizedNewtypeDeriving
-                     , TypeFamilies
-                     , MultiParamTypeClasses
-                     , FlexibleContexts
-                     , FlexibleInstances
-                     , OverloadedStrings
-                     , TemplateHaskell
-  build-depends:       base >=4.7 && <5.0
-                     , yesod-core
-                     , yesod-form
-                     , containers
-                     , transformers
-                     , shakespeare
-                     , text
-                     , blaze-html
-                     , time
-                     , email-validate
-                     , lens-family-th
-                     , lens-family-core
-                     , mtl
-                     , either
-                     , MonadRandom
-                     , persistent
-                     , yesod-markdown >= 0.10.0
-                     , conduit
-                     , conduit-extra
-                     , blaze-markup
-                     , yaml
+  exposed-modules:
+      Yesod.Bootstrap.V3
+  build-depends:
+      base >=4.7 && <5.0
+    , yesod-core
+    , yesod-elements
+    , bootstrap-types
+    , transformers
+    , shakespeare
+    , text
+    , blaze-html
+    , blaze-markup
   hs-source-dirs:      src
   default-language:    Haskell2010
