diff --git a/happstack-yui.cabal b/happstack-yui.cabal
--- a/happstack-yui.cabal
+++ b/happstack-yui.cabal
@@ -1,5 +1,5 @@
 Name          : happstack-yui
-Version       : 7351.2.0
+Version       : 7351.3.0
 Category      : Web, Happstack
 Synopsis      : Utilities for using YUI3 with Happstack.
 Homepage      : https://github.com/dag/happstack-yui
@@ -12,10 +12,11 @@
 Description :
   Bundles YUI 3.5.1 and includes a \"combo handler\" for use in
   Happstack which concatenates YUI modules server-side to send in a single
-  HTTP request.  The YUI bundle is embedded in the library with Template
-  Haskell which means the files are served directly from memory, and also
-  that you can compile and deploy a single executable without having to
-  worry about deploying the YUI files as well.
+  HTTP request.  The YUI bundle can be embedded in compiled code with
+  Template Haskell (install with @-fembed@) which means the files are
+  served directly from memory, and also that you can compile and deploy a
+  single executable without having to worry about deploying the YUI files
+  as well.
   .
   The benefits of using this over the Yahoo! CDN is that you can work
   offline and that you can host YUI yourself without sacrificing the
@@ -26,10 +27,11 @@
   means \"Happstack 7, YUI 3.5.1\".  The second part is the major version
   of this package itself, as defined by the Package Versioning Policy.
   .
-  In a future release, the plan is to add more utilities than just a
-  bundled YUI, for example a combo handler for YUI modules written using
-  JMacro, a bridge between HSX and YUI Node objects and tools for working
-  with the YUI CSS modules.
+  The package also includes some utilities for working with the YUI CSS
+  modules.  In a future release, the plan is to add more utilities, for
+  example a combo handler for YUI modules written using JMacro, a bridge
+  between HSX and YUI Node objects and tools for making it easier to work
+  with modules like Uploader and Pjax.
   .
   For an example application, see:
   <https://github.com/dag/happstack-yui/blob/master/demo/happstack-yui-demo.hs>
@@ -2829,6 +2831,10 @@
 bundle/yui-log/yui-log-min.js
 }
 
+Flag embed
+  Description : Embed the YUI bundle in compiled code.
+  Default     : False
+
 Source-Repository head
   Type     : git
   Location : git://github.com/dag/happstack-yui.git
@@ -2837,7 +2843,6 @@
   HS-Source-Dirs   : src
   Default-Language : Haskell2010
   GHC-Options      : -Wall
-  CPP-Options      : -DYUI_VERSION=3.5.1 -DYUI_VERSION_STR="3.5.1"
   Exposed-Modules  :
     Happstack.Server.YUI
   Other-Modules    :
@@ -2847,13 +2852,29 @@
     boomerang             == 1.3.*,
     bytestring            == 0.9.*,
     containers            >= 0.4 && < 0.6,
-    file-embed            == 0.0.*,
     happstack-jmacro      == 7.0.*,
     happstack-server      == 7.0.*,
     jmacro                == 0.5.*,
+    mtl                   >= 2.0 && < 2.2,
     pretty                == 1.1.*,
     template-haskell      >= 2.5 && < 2.8,
     text                  == 0.11.*,
     web-routes            == 0.27.*,
     web-routes-boomerang  == 0.26.*,
     web-routes-happstack  == 0.23.*
+
+  if !flag(embed)
+    CPP-Options   :
+      -DYUI_VERSION=3.5.1
+      -DYUI_VERSION_STR="3.5.1"
+    Other-Modules :
+      Paths_happstack_yui
+    Build-Depends :
+      directory == 1.1.*
+  else
+    CPP-Options   :
+      -DYUI_VERSION=3.5.1
+      -DYUI_VERSION_STR="3.5.1"
+      -DEMBED
+    Build-Depends :
+      file-embed == 0.0.*
diff --git a/src/Happstack/Server/YUI.hs b/src/Happstack/Server/YUI.hs
--- a/src/Happstack/Server/YUI.hs
+++ b/src/Happstack/Server/YUI.hs
@@ -1,27 +1,35 @@
 {-# LANGUAGE CPP, OverloadedStrings, TemplateHaskell, QuasiQuotes #-}
 
 module Happstack.Server.YUI
-  ( implYUISite
-  , bundle
+  ( -- * Combo Handler
+    implYUISite
+    -- * CSS utilities
+  , gridUnit
+  , fontSize
+    -- * Bundle utilities
+  , isYUIFile
+  , readYUIFile
   ) where
 
 import Prelude hiding ((.))
 
 import qualified Data.ByteString as B
-import qualified Data.Map        as Map
 import qualified Data.Text       as T
 
 import Control.Category             (Category((.)))
-import Control.Monad                (liftM, void, mzero)
+import Control.Monad                (guard, liftM, void)
+import Control.Monad.Trans          (liftIO)
 import Data.List                    (intercalate)
+import Data.Ratio                   ((%), numerator,denominator)
 import Data.Text.Encoding           (encodeUtf8)
 import Happstack.Server             (ServerPartT, Response, neverExpires, setHeaderM, badRequest, ok, toResponse, guessContentTypeM, mimeTypes, lookPairs)
 import Happstack.Server.Compression (compressedResponseFilter)
 import Happstack.Server.JMacro      ()
-import Happstack.Server.YUI.Bundle  (bundle)
+import Happstack.Server.YUI.Bundle  (isYUIFile, readYUIFile)
 import Language.Javascript.JMacro   (JStat(BlockStat), jmacro, renderJs, jhFromList, toJExpr)
 import Text.Boomerang.TH            (derivePrinterParsers)
 import Text.PrettyPrint             (Style(mode), Mode(OneLineMode), renderStyle, style)
+import Text.Printf                  (printf)
 import Web.Routes                   (Site, RouteT, showURL)
 import Web.Routes.Boomerang         (Router, (<>), (</>), rList, anyString, eos, boomerangSiteRouteT)
 import Web.Routes.Happstack         (implSite)
@@ -98,32 +106,96 @@
     void compressedResponseFilter
     case url of
       BundleURL paths ->
-        do let filepath = intercalate "/" paths
-           mime <- guessContentTypeM mimeTypes filepath
+        do let name = intercalate "/" paths
+           exists <- liftIO $ isYUIFile name
+           guard exists
+           mime <- guessContentTypeM mimeTypes name
            setHeaderM "Content-Type" mime
-           maybe mzero (ok . toResponse) $ Map.lookup filepath bundle
+           bytes <- liftIO $ readYUIFile name
+           ok . toResponse $ bytes
       ComboHandlerURL ->
         do qs <- liftM (map fst) lookPairs
-           if null qs || any (`Map.notMember` bundle) qs
+           exists <- liftIO $ mapM isYUIFile qs
+           if null qs || any (== False) exists
              then badRequest $ toResponse ()
              else do mime <- guessContentTypeM mimeTypes $ head qs
                      setHeaderM "Content-Type" mime
-                     ok $ toResponse $ B.concat $ map (bundle Map.!) qs
+                     bytes <- liftIO $ mapM readYUIFile qs
+                     ok $ toResponse $ B.concat bytes
       CSSComboURL ->
         do qs <- liftM (map (css . fst)) lookPairs
-           if null qs || any (`Map.notMember` bundle) qs
+           exists <- liftIO $ mapM isYUIFile qs
+           if null qs || any (== False) exists
              then badRequest $ toResponse ()
              else do setHeaderM "Content-Type" "text/css"
-                     ok $ toResponse $ B.concat $ map (bundle Map.!) qs
+                     bytes <- liftIO $ mapM readYUIFile qs
+                     ok $ toResponse $ B.concat bytes
       ConfigURL ->
         do config <- mkConfig
            ok $ toResponse config
       SeedURL ->
         do config <- mkConfig
+           seed <- liftIO $ readYUIFile "yui/yui-min.js"
            setHeaderM "Content-Type" "application/javascript"
            ok $ toResponse $ seed `B.append` (encode . render) config
   where
-    seed   = bundle Map.! "yui/yui-min.js"
     render = renderStyle (style { mode = OneLineMode }) . renderJs
     encode = encodeUtf8 . T.pack
     css fn = "css" ++ fn ++ "/css" ++ fn ++ "-min.css"
+
+-- | Gets the class name for the grid unit of the ratio of the two argument
+-- integers.  YUI doesn't define redundant classes like \"6\/24\" because
+-- that is the same as 1\/4 and presumably for sake of a smaller CSS file.
+-- This helper function handles that for you, though:
+--
+-- >>> gridUnit 6 24
+-- "yui3-u-1-4"
+--
+-- The intention is for this function to be used in templates to create
+-- values for class attributes, for example with HSP:
+--
+-- ><div class=(gridUnit 6 24)>
+-- >  <% someContent %>
+-- ></div>
+gridUnit :: Integer -> Integer -> T.Text
+gridUnit n d =
+    T.concat [ "yui3-u-"
+             , T.pack . show . numerator $ n % d
+             , "-"
+             , T.pack . show . denominator $ n % d
+             ]
+
+-- | Converts a pixel size to a percentage suitable for use
+-- with the CSS fonts module:
+--
+-- >>> fontSize 16
+-- "123.1%"
+--
+-- Useful in generated stylesheets, for example with HSP:
+--
+-- ><style>
+-- >  h1 { font-size: <% fontSize 26 %> }
+-- ></style>
+fontSize :: Integer -> T.Text
+fontSize 10 = "77%"
+fontSize 11 = "85%"
+fontSize 12 = "93%"
+fontSize 13 = "100%"
+fontSize 14 = "108%"
+fontSize 15 = "116%"
+fontSize 16 = "123.1%"
+fontSize 17 = "131%"
+fontSize 18 = "138.5%"
+fontSize 19 = "146.5%"
+fontSize 20 = "153.9%"
+fontSize 21 = "161.6%"
+fontSize 22 = "167%"
+fontSize 23 = "174%"
+fontSize 24 = "182%"
+fontSize 25 = "189%"
+fontSize 26 = "197%"
+fontSize px =
+    T.pack . printf "%.1f%%" $ percentage
+  where
+    percentage :: Double
+    percentage = fromIntegral px * (100 / 13)
diff --git a/src/Happstack/Server/YUI/Bundle.hs b/src/Happstack/Server/YUI/Bundle.hs
--- a/src/Happstack/Server/YUI/Bundle.hs
+++ b/src/Happstack/Server/YUI/Bundle.hs
@@ -1,11 +1,41 @@
-{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE CPP, TemplateHaskell #-}
 
-module Happstack.Server.YUI.Bundle where
+module Happstack.Server.YUI.Bundle
+  ( isYUIFile
+  , readYUIFile
+  ) where
 
 import Data.ByteString (ByteString)
-import Data.FileEmbed  (embedDir)
-import Data.Map        (Map, fromList)
 
--- | Maps the filenames of the bundled YUI build to their contents.
+#if EMBED
+import Data.FileEmbed            (embedDir)
+import Data.Map                  (Map, (!), fromList, member)
+#else
+import Paths_happstack_yui       (getDataFileName)
+import System.Directory          (doesFileExist)
+import qualified Data.ByteString as B
+#endif
+
+#if EMBED
 bundle :: Map FilePath ByteString
 bundle = fromList $(embedDir "bundle")
+#endif
+
+-- | Tells if a file is included in the YUI bundle.
+--
+-- >>> isYUIFile "yui/yui-min.js"
+-- True
+isYUIFile :: FilePath -> IO Bool
+#if EMBED
+isYUIFile name = return $ member name bundle
+#else
+isYUIFile name = getDataFileName ("bundle/" ++ name) >>= doesFileExist
+#endif
+
+-- | Reads the contents of a file included in the YUI bundle.
+readYUIFile :: FilePath -> IO ByteString
+#if EMBED
+readYUIFile name = return $ bundle ! name
+#else
+readYUIFile name = getDataFileName ("bundle/" ++ name) >>= B.readFile
+#endif
