Last week or so a reader asked if I would quickly demonstrate how I use custom tags for layout. This is something I've done for many years now and is typically how I how handle ensuring a web site can easily maintain a consistent look. The idea is simple - use the fact that custom tags can "wrap" other content. How is this done? Consider this code block:
<cf_bold>When will the fall season start?</cf_bold>
The custom tag, bold, is used at the beginning and the end of the text block. The last tag is used with a slash just like you see in normal HTML tags that wrap content.
ColdFusion provides a ThisTag scope that provides information about the custom tag. In this case, it tells us if the tag is in a start or end mode. This is done via the executionMode value. So let's look at a layout custom tag. I call this my Pretty in Pink theme:
<cfif thisTag.executionMode is "start">
<html>
<head>
<title>Test</title>
</head>
<body bgcolor="#d95ff3">
<cfelse>
</body>
</html>
</cfif>
The file is split in half with the CFIF statement. The first half runs when thisTag.executionMode is "start", and the second half will run when it is "end" (or any value really, but that's the only other value). So to use my layout tag, I can simply do this:
<cf_layout>
This is a test.
</cf_layout>
Now typically my layout tags perform a bit more work. For example - they typically display a title as well. Consider this modified version:
<cfparam name="attributes.title" default="">
<cfif thisTag.executionMode is "start">
<html>
<head>
<cfoutput><title>#attributes.title#</title></cfoutput>
</head>
<body bgcolor="#d95ff3">
<cfoutput><h1 style="color: white;">#attributes.title#</h1></cfoutput>
<cfelse>
</body>
</html>
</cfif>
All I've done is defined a variable, attributes.title, and then I use that in both the head area and within an H1 tag. To use this attribute, I just change my files to do this:
<cf_layout title="The 1980s are Superbad!">
This is a test.
</cf_layout>
So that's it. Just a quick note - this can be useful in cases even when you use CSS for everything (markup and layout). Even in 100% pure CSS sites, you still need a head block, you still need to point to the CSS file, etc. So I'd still use the layout tag to get those items into the file.
Archived Comments
Hi Ray, I've seen you use this for years in many of your applications. While I understand it helps modulize I never understood the advantage over using includes. It always seemed to me to be a larger amount of overhead with no real benefit. Maybe you could explain why you would use this over simple includes?
"larger overhead" is up to opinion. Certainly a CT takes more processing than an include, but I don't think it is something to be concerned about. CTs got a bad rep in the 4.x days because they were overused but I think their overhead is nothing to be terribly concerned about.
That being said - using CT as opposed to header or footer file feels better to me. I like how I have the template in one file. This makes it easier to debug layout issues too as I don't have to switch between two files.
@TJ - I actually use this method quite a bit with includes in the custom tag (when I have multiple layout CTs and want to reuse display components). Granted, I haven't done extensive performance testing but its never caused any issues for me.
I'm sure it all comes down to personal preference tho...
A very powerful and awesome characteristic of custom tags is the ability to nest other custom tags within them. For example, I have a custom tag that creates a formatted container with a title area, content area, and so on:
<ui:Container Title="PodTitle">
This is content in the pod
</ui:Container>
Sometimes, I display search results in the container and I need to have some sort of pagination. So I built a sub-tag to my container tag:
<ui:Container Title="PodTitle">
<ui:Pagination StartRow="21" MaxRows="20">
This is content in the pod
</ui:Container>
In this code snippet, the 'container' tag reads the 'pagination' tag, and creates a perfectly and consistently formatted pagination element within it.
I prefer using custom tags over includes for layout. On the off chance you needing to pass any sort of information I think it's much cleaner and more readable to pass variables in as attributes of a custom tag than it is to set variables before your include.
And with Application.cfc being able to define this.mappings['/blah'] and this.customTagPaths - this only gets easier now. I use something similiar to this at work myself. It lets me worry about building applications than worrying about what the rest of the site is going to look like. I can plop down a valid xhtml website and worry about the overall site design later.
An advantage of custom tags over includes is that they run in their own memory space so your are ensured that you will not have variable name conflicts.
They use this method at my shop. I came from a PHP environment where we used includes to do the same work, and I can't say that I like the custom tag method. It's cumbersome and it required a hell of a workaround when I wanted to use a custom CF error page. Pages should work like this (in my opinion):
<do any page action/>
<set page specific vars/>
<header include/>
<content/>
<footer include/>
I have used something like this as well for many years, though I have one twist -- rather than just outputting the "header", then the body, then the "footer" I use the thisTag.generatedContent variable to gather what is between the tags, then output that when the end tag executes. This allows great flexibility to do things like have a global "error message" mechanism that can be called anywhere on any page but always show up at the "top" of a user's page or things like impacting the navigation of the page based on something that happens inside the page content. It has also come in handy when doing things like putting in gzip on a page-by-page basis inside my CFML.
Why not put the tag start and end between the first and last <head> section. I always do this to put extra javascript or style information in there if I need it only on a particular page.
<cf_header>
</cf_header>
:executionmode start:
<html>
<head>
:executionmode end:
put extra head information here
</head>
<body>
I do not trust the cfheader tag for this because I had major issues with this tag using proxy servers and firewalls years ago :-) maybe it's better these days but I stick with this method because it works like a charm.
I was wondering if CF8 cfdiv will have any effect on the way you do your layout...
Michael, that question could have a lot of answers - but basically no, it won't. I will use cf_ instead of cfmodule though for sites I know are launching on cf8 sites.
I use this method for page layout as well, since it looks neater than a bunch of cfsets and includes. However, my custom tag itself contains almost no HTML-- those are called in via includes. It's easier and less disruptive to update smaller files that are included rather than to embed all of your layout code in the custom tag.
CTs are also easier to call than includes and also very easy to remove from your web root directory (it's hard to enjoy doing ../../../../.. this). The fact that they they have scope and "stackability" is very important. I also think it makes server scripts look more elegant. Learning how to use the "generatedContent" variable is also important.
I can see how this sort of speak might make some programmers cringe ... but the productivity, elegance, and learning curves are hard to ignore.
Oops ... sorry I didn't realize that was an old post.
Sandboxing variables is the advantage over cfinclude. Sandboxing also occurs in cfmodule...but I use cfinclude aswell!