Custom Tags in ColdFusion

8 March 2021

One of the greatest things about ColdFusion is the way it allows you to extend the CFML language. You can create your own tags, functions, and components and allow them to be used across your enterprise. For the purposes of this lesson, I will be focusing on custom tags only.

Imagine if you could create a new HTML tag and allow anyone in your organization to be able to use it in their web pages. Well, with ColdFusion, you can do that and more. Custom tags are code that you encapsulate into a CFML page and the call similarly to cfoutput or cfdump. In the Getting started lesson, I mentioned trying to create your applications for code reuse. Custom tags are a great way to do this. Let's explore this for a minute.

A simple scenario: Imagine you are creating a website for, oh...I don't know...a college. If each department in that college needed the same element on every page - like a footer that contains the same links across the whole site - you could create the footer as a seaprate CFML file and use cfinclude to include the footer contents into every page. This gives you the ability to edit one file and have it update across the whole site. Included files have been around for a long time. Back in the beginning we had server-side includes which required the shtml file extension. Never seen that one before? Yeah, it's hardly used anymore. With includes in ColdFusion you just use the cfinclude and that's it. The only thing you need to know when creating includes - they should never contain a body or any other of the default HTML tags. It is best to start with a completely blank page when creating an include. Since you are adding them to a page that already has the HTML body, etc. your include will inherit it from the including page. Here's a quick example of including that footer file in your page:


<cfinclude template = "templates/footer.cfm">

I use tons of includes. Header, navigation, body contents, usually are all pulled from included files. Why? I like to try to separate my CFML from the layout or display layer of the sites I create. If there is an update or error, I know I can open one file, update the code without having to scroll through an entire page. However, cfinclude has a few limitations. That's where custom tags come into play.

A custom tag is basically an include that you can pass data into and retrieve data from. I use the heck out of these things too. If there is a chunk of code that would benefit the whole team, I find a way to create a custom tag for it. Our CAC login pages all use my jpCAC custom tag. My tags always start with jp just so you know who to complain to if they cause you issues.

So, on the same college site, let's say each department needs a custom menu that pulls information from a database. Department A has a set of links and so does department B...so you might just create separate menus for each department. But, man, that is a lot of code to keep track of. If someone decides that all menus need to be blue instead of grey you would need to update a ton of files with the same update. With a custom tag you would just have one working menu, feed in the department's unique identifier from the database, and the tag will construct the menu for you. This is exactly how the AFIT website works.

Okay, enough blathering on about the theory. Let's create a simple custom tag to create a colored div block that displays some text.

Like include files, we start with a blank page. First we start with our list of attributes. The attributes variable scope is used specifically within the custom tag and define the attributes of the tag - like the class attribute in an HTML div tag, etc.


<cfparam name="attributes.color" default="##CCCCCC">
<cfparam name="attributes.height" default="auto">
<cfparam name="attributes.width" default="200px">
<cfparam name="attributes.center" default="true">
<cfparam name="attributes.text" default="This is my default text.">

These five attributes will control what the output of the custom tag looks like. We will feed the values we want to change from their default values into the tag and it will output the div accordingly.

Now we will add some CSS to the custom tag and feed the attributes in.


<style>
.myblock{
	width:<cfoutput>#attributes.width#</cfoutput>;
	height:<cfoutput>#attributes.height#</cfoutput>;
	background-color:<cfoutput>#attributes.color#</cfoutput>;
	padding:20px;
	<cfif attributes.center IS 'true'>text-align:center;</cfif>
	}
</style>

Pretty basic. We just add the attribute values to the CSS. We have a cfif in there to center the text if the attribute is true. Now let's create our block div tag.


<div class="myblock d-block"><cfoutput>#attributes.text#</cfoutput></div>

You can see we are just feeding the name of the CSS class myblock into the div and let the CSS do what it does. I also included the d-block Bootstrap class in there. I am using Bootstrap in this site so that jst tells the div to display as a block.

So the completed tag would look like:


<cfparam name="attributes.color" default="##CCCCCC">
<cfparam name="attributes.height" default="auto">
<cfparam name="attributes.width" default="200px">
<cfparam name="attributes.center" default="true">
<cfparam name="attributes.text" default="This is my default text.">

<style>
.myblock{
	width:<cfoutput>#attributes.width#</cfoutput>;
	height:<cfoutput>#attributes.height#</cfoutput>;
	background-color:<cfoutput>#attributes.color#</cfoutput>;
	padding:20px;
	<cfif attributes.center IS 'true'>text-align:center;</cfif>
	}
</style>

<div class="myblock d-block"><cfoutput>#attributes.text#</cfoutput></div>

Now we need to call the custom tag. There are two ways to do this in ColdFusion. We can call the tag directly or use another ColdFusion tag to call it. ColdFusion looks for custom tags in three places in this order:

  1. The directory of the calling page.
  2. The ColdFusion custom tag directory within the server's install root. You typically don't have access to this so talk to me if you need one added to the library.
  3. Any custom custom tag directory in ColdFusion Administrator - the control panel accessible by the server admin.
  4. You can also specify a custom tag directory in your application.cfc - which is for another lesson.

Custom tags are called into a page directly with the following syntax:


<cf_jpBlock color="##FFCC00" text="This is my block in gold.">

Notice the way the tag looks. All custom tags start with cf_ which makes it easy to tell custom tags from standard ColdFusion tags. The tag would process and give us...

This is my block in gold.

Pretty cool huh? The easiest way to include your custom tags without access to the ColdFusion install directory is to use the cfmodule tag. You tell it where the tag template page is and add your attributes like so:


<cfmodule template="mytags/jpBlock.cfm" color="##FFCC00" text="This is my block in gold.">

This way allows you to keep your tags within your application and not rely on the server admin to upload and maintain them for you. If your tags are specific to your application this is a best practice. If the tags would benefit others in your team you would need to have them added to the global library - which means they can be used in any application on the server!

Sometimes you want ColdFusion to process and return data to your app instead of just displaying HTML. Let's create one of these. In the Getting Started lesson, I showed the math to calculate the area of a circle. We'll use that math and feed the radius into the custom tag and have ColdFusion spit back the result.


<cfparam name="attributes.radius" default="10">

<cfset area = pi()*attributes.radius^2>
<cfset caller.thearea = "#decimalFormat(area)#">


Now we call it - I'll use the cfmodule tag here - and output the data.


<cfmodule template="mytags/jpArea.cfm" radius="20">

The area of the circle is <cfoutput>#thearea#</cfoutput> square feet.

See the caller variable scope. This scope is only for custom tags. It sends the data back to the calling page of the tag for use. This gives us:

The are of the cirle is 1,256.64 square feet.

With the caller scope you can send back any data you like. Queries, structures, arrays, anything you need.

The last tidbit is to always add a comment block at the top of the tag that tells what it does and what each attribute is for. This helps other developers and yourself remember how to use a tag long after it's creation.

We have a pretty extensive library of custom tags on our servers. Several of which are very powerful. I created one called jpEncrypto that can be used to encrypt and decrypt data on the fly - and we will use that in the cookies lesson.

The AFIT public site uses custom tags often to create dynamic menus and content when I feed in a department's unique identifier. This allows me to control how data is dislpayed from one location and display the proper information. Custom tags allow us to create tags for our own specific uses if no existing ColdFusion tag will fit the bill and in some cases simplify some of the more arduous coding in ColdFusion.

-Jack