At snapframework.com, we do this using javascript. At the end of site.js you will find this code that will add the appropriate class to the corresponding link.
if ($.url.segment(0)) { $('.nav li.'+$.url.segment(0)).addClass('active'); } else { $('.nav .home').addClass('active'); }
If you want to do this with Heist, you will need to use a paradigm slightly different from what your template uses. The whole point of Heist (with a strong static system like Haskell) is to ensure the greatest possible separation between presentation and business logic, so you cannot use Haskell constructs, such as loops or conditional expressions, directly in your templates. The answer is to create a new tag (implemented using splicing) that does exactly what you want. In your template, you will use it as follows:
<ul> <menuLink href="/">Home</menuLink> <menuLink href="/about">About Us</menuLink> </ul>
First of all, pay attention to how much cleaner it is. In your approach, you had to repeat the same code for each link. Here we can save the DRY pattern, and it reads pretty well.
To implement the menuLink tag, you need a splice splice that looks something like this:
import Control.Monad.Trans.Class (lift) -- transformers import Data.Text.Encoding (decodeUtf8) import Text.XmlHtml (getAttribute, setAttribute, elementTag) menuLinkSplice :: MonadSnap m => HeistT m Template menuLinkSplice = do requestPath <- lift $ withRequest (return . rqURI) node <- getParamNode let addActive n = if getAttribute "href" n == Just (decodeUtf8 requestPath) then setAttribute "class" "active" n else n return [addActive (node { elementTag = "a" })]
Then, to put it all together, you need to associate this splicing with the menuLink tag. In the Snap app, you do this with:
addSplices [ ("menuLink", liftHeist menuLinkSplice) ]
You can also find the blog post "Looping and Control Flow in Heist" (like some of my other posts with "heist" tag).