Widgets in Yesod are a way to add some nice features – like order independence – to created parts of page.  That’s because Widgets are more semantic elements than a set of tags – they also contain some information about tag location – for example if it should be inserted in the header or body of the page. For example, let’s assume we want to add a button that will redirect from each detailed project page to the list of all projects.

To do this, we’re gonna create a Hamlet template (in templates/back-to-projects.hamlet) for the widget first. It’ll contain the following code:

<div .comeback-link>
  <a .btn .btn-default href="@{ProjectsR}" role="button">Back to project list

Then let’s create a Cassius template (templates/back-to-projects.cassius) for styles:

.comeback-link
  margin-top: 10px
  margin-bottom: 10px

And in the end let’s use these templates in our Handler/Project.hs:

renderPage :: (Int, Text) -> Widget
renderPage projectEntry = do
  setTitle $ ("Project " ++ projectTitle)
  $(widgetFile "project")
  $(widgetFile "back-to-projects")
  where
    projectTitle = (toHtml projectId) ++ (toHtml projectName)
    projectName = snd projectEntry
    projectId = fst projectEntry

As a result, we get a nice button below the description of the project – this way we can add widget after widget to the page. Of course, we can also compose them to create bigger widgets. Now, that’s not something very interesting – after all we just added a piece of HTML below our previous HTML and it appeared below, so what’s the fun? Well, a bit of fun happens with the stylesheet and JS files (we don’t have a JS file here). Stylesheet got minified and added to the page stylesheet, returned in the header. If we had a JS file, it would also be included as a script (or file, depends on configuration) in the header. Of course, it may be that you actually want the JS to appear in the body – for this, Yesod offers toWidgetBody and toWidgetHead functions, which let you modify HTML head and body respectively. Widgets can be used not only for web pages – there are also functions – like toWidgetMedia that can help you create all other types of data, including print styling or API.

One more note – if you wonder what a Widget is, it is just an alias for WidgetT <<AppName>> IO (), where <<AppName>> can be defined in Application.hs (by default it’s MyApp). It is important to note that Widget is typed per-application. And we’ll discuss why exactly is it important next week, when discussing foundation datatype.

Stay tuned!