diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,8 @@
+The original author of this library is Jeremy Yallop. It is currently maintained
+by Chris Eidhof.
+
+Other contributors:
+* MightyByte
+* Eelco Lempsink
+
+The formlets repository is hosted on github: http://github.com/chriseidhof/formlets/
diff --git a/Text/Formlets.hs b/Text/Formlets.hs
--- a/Text/Formlets.hs
+++ b/Text/Formlets.hs
@@ -1,15 +1,16 @@
-module Text.Formlets ( input', inputFile, fmapFst, nothingIfNull
+module Text.Formlets ( input', optionalInput, inputFile, fmapFst, nothingIfNull
                      , check, ensure, ensures
                      , ensureM, checkM, pureM
                      , runFormState 
                      , massInput
                      , xml, plug
                      , withPrefix
-                     , Env , Form , Plus (..)
+                     , Env , Form
                      , File (..), ContentType (..), FormContentType (..)
                      )
                      where
 
+import Data.Monoid
 import Control.Applicative
 import Control.Applicative.Error
 import Control.Applicative.State
@@ -31,10 +32,6 @@
                                }
                                deriving (Eq, Show, Read)
 
-class Plus a where
-  zero      :: a
-  plus      :: a -> a -> a
-
 -- | Apply a predicate to a value and return Success or Failure as appropriate
 ensure :: Show a 
        => (a -> Bool) -- ^ The predicate
@@ -73,6 +70,14 @@
          fromLeft n (Just (Left x)) = Success x
          fromLeft n _               = Failure [n ++ " is a file."]
 
+optionalInput :: Monad m => (String -> xml) -> Form xml m (Maybe String)
+optionalInput i = Form $ \env -> mkInput env <$> freshName
+   where mkInput env name = (return . fromLeft name . (lookup name),
+                             return (i name), UrlEncoded)
+         fromLeft n Nothing         = Success Nothing
+         fromLeft n (Just (Left x)) = Success (Just x)
+         fromLeft n _               = Failure [n ++ " could not be recognized."]
+
 -- | A File input widget.
 inputFile :: Monad m 
           => (String -> xml)  -- ^ Generates the xml for the file-upload widget based on the name
@@ -114,7 +119,7 @@
 fmapFst  f (a, b)    = (f a, b)
 fmapFst3 f (a, b, c) = (f a, b, c)
 
-instance (Monad m, Applicative m, Plus xml) => Applicative (Form xml m) where
+instance (Monad m, Applicative m, Monoid xml) => Applicative (Form xml m) where
    pure = pureF
    (<*>) = applyF
 
@@ -123,7 +128,7 @@
 xml x = Form $ \env -> pure (const $ return $ Success (), return x, UrlEncoded)
 
 -- | Transform the XML component
-plug :: (Monad m, Plus xml) => (xml -> xml1) -> Form xml m a -> Form xml1 m a
+plug :: (Monad m, Monoid xml) => (xml -> xml1) -> Form xml m a -> Form xml1 m a
 f `plug` (Form m) = Form $ \env -> pure plugin <*> m env
    where plugin (c, x, t) = (c, liftM f x, t)
 
@@ -133,16 +138,16 @@
 -- | This form has to have the same variable-names as the original form, but prefixed by the prefix.
 -- | 
 -- | Typically, some client-side code is needed to duplicate the original form and generate a unique prefix.
-massInput :: (Plus xml, Applicative m, Monad m) => (Form xml m (Maybe String)) -> Form xml m a -> ([String] -> xml) -> Form xml m [a]
+massInput :: (Monoid xml, Applicative m, Monad m) => (Form xml m (Maybe String)) -> Form xml m a -> ([String] -> xml) -> Form xml m [a]
 massInput h f showErrors = massInputHelper form showErrors
  where form = (,) <$> f <*> h
 
-massInputHelper :: (Plus xml, Applicative m, Monad m) 
+massInputHelper :: (Monoid xml, Applicative m, Monad m) 
                 => Form xml m (a, Maybe String)  -- The form
                 -> ([String] -> xml)             -- How to show errors
                 -> Form xml m [a]
 massInputHelper f showErrors = join f
-  where join :: (Plus xml, Applicative m, Monad m) => Form xml m (a, Maybe String) -> Form xml m [a]
+  where join :: (Monoid xml, Applicative m, Monad m) => Form xml m (a, Maybe String) -> Form xml m [a]
         join (Form f) = Form $ \env -> start (f env) env
         start :: (Monad m) => State FormState (Collector (m (Failing (a, Maybe String))), xml, FormContentType) -> Env -> State FormState (Collector (m (Failing [a])), xml, FormContentType)
         start f e =     do  currentState <- get
@@ -194,15 +199,15 @@
 orT x UrlEncoded = x
 orT x y          = x
 
-pureF :: (Monad m, Plus xml) => a -> Form xml m a
-pureF v = Form $ \env -> pure (const (return $ Success v), return zero, UrlEncoded)
+pureF :: (Monad m, Monoid xml) => a -> Form xml m a
+pureF v = Form $ \env -> pure (const (return $ Success v), return mempty, UrlEncoded)
 
-pureM :: (Monad m, Plus xml) => m a -> Form xml m a
-pureM v = Form $ \env -> pure (const (liftM Success v), return zero, UrlEncoded)
+pureM :: (Monad m, Monoid xml) => m a -> Form xml m a
+pureM v = Form $ \env -> pure (const (liftM Success v), return mempty, UrlEncoded)
 
-applyF :: (Monad m, Applicative m, Plus xml) => Form xml m (a -> b) -> Form xml m a -> Form xml m b
+applyF :: (Monad m, Applicative m, Monoid xml) => Form xml m (a -> b) -> Form xml m a -> Form xml m b
 (Form f) `applyF` (Form v) = Form $ \env -> combine <$> f env <*> v env
-  where combine (v1, xml1, t1) (v2, xml2, t2) = (first v1 v2, (plus <$> xml1 <*> xml2), t1 `orT` t2)
+  where combine (v1, xml1, t1) (v2, xml2, t2) = (first v1 v2, (mappend <$> xml1 <*> xml2), t1 `orT` t2)
         first v1 v2 e = do x <- v1 e 
                            y <- v2 e
                            return $ x <*> y
diff --git a/Text/XHtml/Strict/Formlets.hs b/Text/XHtml/Strict/Formlets.hs
--- a/Text/XHtml/Strict/Formlets.hs
+++ b/Text/XHtml/Strict/Formlets.hs
@@ -1,6 +1,7 @@
 module Text.XHtml.Strict.Formlets ( input, textarea, password, file
                                   , hidden, inputInteger, radio, enumRadio
-                                  , selectRaw, select
+                                  , label
+                                  , selectRaw, select, enumSelect
                                   , XHtmlForm
                                   , module Text.Formlets
                                   ) where
@@ -14,10 +15,6 @@
 
 type XHtmlForm m a = Form X.Html m a
 
-instance Plus X.Html where
-  zero = X.noHtml
-  plus = (+++)
-
 -- | An input field with an optional value
 input :: Monad m => Maybe String -> XHtmlForm m String
 input = input' (\n v -> X.textfield n ! [X.value v])
@@ -58,6 +55,8 @@
  where toS = fmapFst (show . fromEnum)
        convert v = maybeRead' v "Conversion error" 
 
+label str = xml $ X.label $ X.toHtml str
+
 selectRaw :: Monad m => [(String, String)] -> Maybe String -> XHtmlForm m String
 selectRaw choices = input' mkChoices -- todo: validate that the result was in the choices
  where mkChoices name selected = X.select ! [X.name name] $ X.concatHtml $ map (mkChoice selected) choices
@@ -73,3 +72,6 @@
        convert i      | i >= length ls || i < 0 = Failure ["Out of bounds"]
                       | otherwise               = Success $ fst $ ls !! i
        asInt   s      = maybeRead' s (s ++ " is not a valid int")
+
+enumSelect :: (Show a, Bounded a, Enum a, Eq a) => Maybe a -> XHtmlForm IO a
+enumSelect = select (zip items (map show items)) where items = [minBound ..]
diff --git a/formlets.cabal b/formlets.cabal
--- a/formlets.cabal
+++ b/formlets.cabal
@@ -1,5 +1,5 @@
 Name:            formlets
-Version:         0.4.7
+Version:         0.4.8
 Synopsis:        Formlets implemented in Haskell
 Description:     A modular way to build forms based on applicative functors, as
                  described in:
@@ -17,4 +17,10 @@
 Exposed-Modules:   Text.Formlets
                  , Text.XHtml.Strict.Formlets
 Build-Type:      Simple
-Build-Depends:   base, haskell98, mtl, xhtml, applicative-extras, bytestring
+Build-Depends:   base, 
+                 haskell98, 
+                 mtl, 
+                 xhtml, 
+                 applicative-extras >= 0.1.3, 
+                 bytestring
+Extra-Source-Files: README
