The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.


Catalyst::View::Seamstress - HTML::Seamstress View Class for Catalyst


# use the helper to create MyApp::View::Seamstress # where comp_root and skeleton are optional view Seamstress Seamstress /path/to/html html::skeleton
                         ^-modulenm ^-helpernm ^-comp_root   ^-skeleton

# optionally edit the skeleton and meat_pack routines # in lib/MyApp/View/

# create your seamstress template packaged with # see HTML::Seamstress.. This will give you a .pm file to go with your html, # so something like html::helloworld

# render view from lib/ or lib/

    sub message : Global {
        my ( $self, $c ) = @_;

        # LOOM points to our template class made with or
        # manually:
        $c->stash->{LOOM} = 'html::hello_world';
        $c->stash->{name}     = 'Mister GreenJeans';
        $c->stash->{date}     = 'Today';

        # the DefaultEnd plugin would mean no need for this line

# and in your html::helloworld you can do something like:

 sub process{
     my( $tree, $c, $stash ) = @_;
     $tree->look_down( id => 'name' )->replace_content( $stash->{name} );


This is the Catalyst view class for HTML::Seamstress. It allows templating with proper seperation between code and HTML. This means you can get a designer/friend/client/stooge to make your templates for you without having to teach them a mini-language!

Your application should define a view class which is a subclass of this module. The easiest way to achieve this is using the script (where myapp should be replaced with whatever your application is called). This script is created as part of the Catalyst setup.

    $ script/ view Seamstress Seamstress

This creates a module in the lib directory (again, replacing MyApp with the name of your application).

Now you can modify your action handlers in the main application and/or controllers to forward to your view class. You might choose to do this in the end() method, for example, to automatically forward all actions to the Seamstress view class.

    # In MyApp or MyApp::Controller::SomeController

    sub end : Private {
        my( $self, $c ) = @_;

Or you might like to use Catalyst::Plugin::DefaultEnd

..or even Catalyst::Action::RenderView


The helper app automatically puts the per-application configuration info in MyApp::View::Seamstress. You configure the per-request information (e.g. $c->stash->{LOOM} and variables for this template) in your controller.

The two main options which control how View::Seamtress renders HTML are the LOOM (which is taken from the stash) and optionally the skeleton, which is stored in the app config.

If you just configure a LOOM then you are most likely using the "plain meat" method described below. If you also configure a skeleton in your config as well then you're using the "meat and skeleton" method. See below for a more detailed discussion of this!

  • $c->stash->{LOOM}

    The Seamstress view plugin MUST have a LOOM to work on or it will balk with an error:

        sub message : Global {
            my ( $self, $c ) = @_;
            $c->stash->{LOOM} = 'html::hello_world';
            $c->stash->{name}     = 'Billy Bob';
            $c->stash->{date}     = 'medjool sahara';
  • MyApp::View::Seamstress->config->{skeleton}

    By default this is not set and the HTML output is simply the result of taking $c->stash->{LOOM}, calling new() to create an HTML tree and then passing this to process() so that it can rework the tree.

    However, if MyApp::View::Seamstress->config->{skeleton} is set, then both its value and the values of MyApp::View::Seamstress->config->{meat_pack} and $stash->{LOOM}->fixup() come into effect as described in "The_meat-skeleton_paradigm" in HTML::Seamstress.

    Let's take that a little slower: $stash->{LOOM}->fixup() means: given a Seamstress-style Perl class, whose name is $stash->{LOOM}, call the method fixup() in that class so that it can do a final fixup of the entire HTML that is about to be shipped back to the client.

The output generated from the LOOM (and possibly its interaction with a skeleton) is stored in $c->response->body.

Other Config Options


Set this to a coderef to allow the view to change the tree after the main processing phase.


By default the view will generate html 4 style html by calling as_HTML on the tree object. If you set this to a true value it will generate XHTML style HTML by calling as_XML on the tree object. See HTML::Element for details for these methods.

Also note that this won't apply proper HTML doctypes and what-have-you unless you have them in your original HTML.


This is the subref which is called to pack meat into the skeleton for the meat skeleton method. Tinker with this to have more creative LOOMS. See "Funny LOOMs" and the meat/skeleton discussions.

Funny LOOMs

In the examples so far the LOOM has always been a class name.

If instead LOOM is an object then we'll assume that is a useful HTML::Element style object and just use that instead of calling new on the LOOM. In this case we'll also not ->delete it at the end of the request so you'll have to do that yourself!

If the LOOM is in fact an ARRAY reference filled with class names we'll send the meat_pack a hash of class names mapped to objects.

The meat-skeleton paradigm

Generally Catalyst::View::Seamstress operates in one of 2 ways: a plain meat way or a meat-skeleton way.

Plain meat is simple: the View takes $c-stash->{LOOM} > and calls new() and process() on it and stores the result in $c-response->body>.

Meat-skeleton is designed to facilitate the way that most web sites are typically designed:

HTML pages typically have meat and a skeleton. The meat varies from page to page while the skeleton is fairly (though not completely) static. For example, the skeleton of a webpage is usually a header, a footer, and a navbar. The meat is what shows up when you click on a link on the page somewhere. While the meat will change with each click, the skeleton is rather static.

Mason accomodates the meat-skeleton paradigm via an autohandler and $m->call_next(). Template accomodates it via its WRAPPER directive.

And Seamstress? Well, here's what you _can_ do:

1 generate the meat, $meat

This is typically what you see in the body part of an HTML page

2 generate the skeleton, $skeleton

This is typically the html, head, and maybe some body

3 put the meat in the skeleton

So, nothing about this is forced. This is just how I typically do things and that is why Catalyst::View::Seamstress has support for this.

Tips to View Writers

The order of use base is VERY significant

When your helper module creates MyApp::View::Seamstress it is very important for the use base to look this way:

  use base qw(Catalyst::View::Seamstress HTML::Seamstress );

and not this way:

  use base qw(HTML::Seamstress Catalyst::View::Seamstress );

so that certain calls (probably new) get handled properly.

Getting config information from MyApp and MyApp::View::*

assuming Catalyst::View::Seamstress::new() starts off like this:

 sub new {
    my $self = shift;
    my $c    = shift;

$self->config contains things set in MyApp::View::*. $c->config contains things set in MyApp

assuming Catalyst::View::Seamstress::process() starts off similarly:

 sub process {
    my ( $self, $c ) = @_;

$self->config contains things set in MyApp::View::*. $c->config contains things set in MyApp.

There is no automatic merging of the two sources of configuration: you have to do that yourself if you want to do it.


Catalyst, Catalyst::View, Catalyst::Helper::View::Seamstress, HTML::Seamstress

A working sample app

The best way to see a fully working Seamstress-style Perl class is to pull down the working sample app from sourceforge.

A working sample app, which does both simple and meat-skeleton rendering is available from github:

 git clone   git://


Email the author or ping him on #catalyst on


Terrence Brannon <>

With some additional hacking by:

Joe Higton <>


This program is free software, you can redistribute it and/or modify it under the same terms as Perl itself.