ColdFusion Custom Tag Tips

Now a days it seems like every one talks about CFCs, or UDFs, and almost no one talks about custom tags. While they are a bit slower than CFCs or UDFs, custom tags are still pretty darn handy. Here are a few tips for people writing custom tags.

  1. Watch your whitespace.

This is more a general ColdFusion tip, but since custom tags tend to be used inside other documents (otherwise they wouldn't be custom tags), you tend to notice their white space even more, especially if the tag is used inside a loop. I recommend just using cfsetting on top and at the bottom of your file, although be sure to also use cfsetting if you leave your custom tag early.

  1. If your custom tag is not meant to be used in "wrapped" mode, then always include this line as your last line of code:
<cfexit method="exitTag">

If you don't, and someone calls your tag like so, <cf_foo/>, then your tag will execute twice.

  1. While I may use "cf_" format in my examples, I almost never use cf_ when invoking a custom tag. I use cfmodule. This tends to be a bit more wordy, but it means i don't have to worry about "name" confusion. This is where ColdFusion has to look for your custom tag, and could potentially find the wrong one. Not only that, ColdFusion caches the location of the tag, so if you move it, you need to restart ColdFusion. All of this goes away if you use cfmodule.

  2. If you return a value, do not hard code it like so:

<cfset caller.foo = 1>

Rather, make it an attribute so the caller can specify what result to return. For example:

<cfparam name="attributes.result" default="result" type="variableName">

<cfset caller[attributes.result] = now()>

This lets me call the tag like so:

<cf_foo> <cf_foo result="result2"> <cf_foo result="result3">

At the end of those lines, I'd have 3 variables created: result, result2, and result3.

Archived Comments

Comment 1 by todd posted on 8/17/2006 at 11:05 PM

Good tips here. It would be nice to have a quick guide for custom tags. Does one exist somewhere?

Comment 2 by Raymond Camden posted on 8/17/2006 at 11:09 PM

I could hit the little Print button and add ot my guides. Actually, I can just add the link. Count to ten and it will be there.

Comment 3 by Terrence Ryan posted on 8/17/2006 at 11:51 PM

Thanks, Ray. This is really valuable to those of us that are considering reevaluating the way they do encapsulation.

I do have one question though. It's about CFmodule Here (CFMX Coding Standards if the link doesn't come through) http://livedocs.macromedia.... Adobe says Don't use CFmodule.

Now this was written By Sean Corfield I believe. If the two of you disgree, I don't know who to believe. :)

In a more answerable question, wouldn't using cfimport achieve your goals without using cfmodule?

Comment 4 by Raymond Camden posted on 8/17/2006 at 11:59 PM

In general I rank Sean's skills over mine, but I'll disagree here. I believe he was worried about the performance. Custom tags are DEFINITELY slower than UDFs/CFCs. However, I don't think they are a cause for concern for 95% of you (you being my readers), and like anything, if performance is a concern, you want to be careful about _all_ the code you write.

Comment 5 by Terrence Ryan posted on 8/18/2006 at 12:04 AM

So if you're already taking the performance hit for Custom tags in the first place, you might as well go whole hog, and use less ambigous code.

That makes sense to me. Thanks.

Comment 6 by Raymond Camden posted on 8/18/2006 at 12:08 AM

Less amigous? Sorry - can you restate that.

Comment 7 by Terrence Ryan posted on 8/18/2006 at 12:12 AM

I meant of course "ambiguous."

Being ambiguous on the other hand, was unintented.

Comment 8 by Steve Bryant posted on 8/18/2006 at 12:13 AM

I believe Sean argues for cf_ or cfimport syntax over cfmodule.

For my part, it depends on the application.

When using global custom tags for applications that have a relatively permanent home, I prefer to call custom tags from the custom tags directory using cf_ format.

If I am developing an application with an eye on distribution, I prefer cfimport so that I can specify the location of the tags more precisely.

The main advantage that I see of cfimport over cfmodule is readability and clarity when nesting tags.

Comment 9 by Ben Nadel posted on 8/18/2006 at 12:14 AM

I have some issues with the whole return variable for custom tags... my feeling is that if it has a return variables, but not just make it UDF, that way you can explicitly use or not use the return value. In my head (which has issues of its own), custom tags are more for page output and the idea of a return variable seems a bit odd. I can understand it for backwards compatibility, but going forward in all the MX stuff and the OOP and the frameworks, does it really make sense to have custom tags that have return variables?

(ps. I am not attacking, I am geninuingly interested in this idea)

Comment 10 by Raymond Camden posted on 8/18/2006 at 12:22 AM

Steve: My concern is that I may not know if the app will go to a single server or a hosted server. THerefore, I never trust cf_ syntax.

cfimport: I don't know why, but it never really turned me on. Maybe it's the fact that you must use the import on EVERY file that needs it.

Ben: I can definitely say that non-display custom tags and UDFs are pretty blurred (I mean the differences between them). I tend to keep my UDFs for shorter blocks of logic, while a more advanced logic block would go into a custom tag. Again though, I do -not- have hard rules for it.

Comment 11 by Steve Bryant posted on 8/18/2006 at 12:28 AM

Ben,

I don't know about Ray, but I have had custom tags that are primarily for output (a function well suited for a custom tag) but also need to return variable.

Ray,

I actually felt the same about cfimport until a recent project (that I finished up around the end of the month...) where I wanted to use some custom tags but cf_ syntax didn't have the flexibility.

I tried cfmodule, but it was just ugly as heck. I tried cfimport and found that I didn't like including it on every page, but it was still well worth the trouble (a surprising change of a long-held opinion for me).

Comment 12 by John Farrar posted on 8/18/2006 at 12:32 AM

Are you sure that when someone calls CFC's in the taggy way of not actually creating an object and accessing it that custom tags are slower? I was thinking they were only faster, but not sure, when you actually create an instance and use the methods rather than <cfinvoke...> the CFC like it was a custom tag. (Please, guys who like CF Invoke... don't get heated... just trying to get a techincal answer, not start a flame war.)

Comment 13 by Ben Nadel posted on 8/18/2006 at 12:32 AM

I happen to love CFImport. I love that you can use good directory paths and it makes grouping tags sooo freakin' nice. For instance, I have a bunch of FORM tags that all have the prefix FORM:

<form:tag disableonsubit="true">
<form:doubleselect name="" value="" .... />
<form:dateselectcalendar name="" ... />
</form:tag>

I just think it makes reading and understanding the code soo much clearer.

Comment 14 by Raymond Camden posted on 8/18/2006 at 12:32 AM

Steve, what do you mean by flexibility? Whether you use cfimport, cf_, or cfmodule, you have the exact same features.

Comment 15 by Steve Bryant posted on 8/18/2006 at 12:37 AM

Sorry I was clear. I meant that cfmodule and cfimport are both are more flexible than cf_ inasmuch as I can specify the exact location of the file I want to use.

With cf_, ColdFusion has a set pattern it follows to find the file. I can't direct it to look where I want.

Comment 16 by Raymond Camden posted on 8/18/2006 at 12:38 AM

John, I'm not sure I read you right. CFINVOKE isn't slower if you use an instance. Ie

<cfinvoke component="#fooo#">

versus

<cfinvoke component="foo">

The second method will make a new CFC. The first one will use an existing CFC and won't have the startup cost.

Comment 17 by John Farrar posted on 8/18/2006 at 12:39 AM

I still like custom tags also... in fact we are working on some custom tags with spry. To me there is "more" power for nested attributes of nested tags in custom tags than there is with CFCs. It's not a case either one being the overall best... but rather which one is best for the task at hand. I like and use them both!

Comment 18 by John Farrar posted on 8/18/2006 at 12:41 AM

Guess we are posting back to back Ray! LOL

That is kinda cool, might have used that tag more but I am one of those guys who likes to do CFScript... so I missed that implementation technique. THANKS!

Comment 19 by Raymond Camden posted on 8/18/2006 at 12:41 AM

Steve: Gotcha.

John: Cool. You love Spry too, right?

I agree - nested tagd are very powerful if used correctly.

Comment 20 by John Farrar posted on 8/18/2006 at 12:42 AM

OK... how do we make the gravitars work Ray?

Comment 21 by Raymond Camden posted on 8/18/2006 at 1:26 AM

You have to register at gravatar.com. GOod luck. It took me 2 months.

Comment 22 by Alan posted on 8/18/2006 at 6:34 PM

It wasn't quite two months ago that I registered at Gravatar. I got the email saying mine was rated G, obviously, if you can actually see it here. Cool idea. (Looking forward to the day we can all pick which comments to skip by glancing at the icons next to them...j/k)
Alan

Comment 23 by Mark Drew posted on 8/18/2006 at 9:12 PM

Ahh, yes.. good posting Ray, I had forgotten about those pesky custom tags (after doing lots of spectra, I am glad to be away from them!) but yes, it reminded me that I need to add some functionality to <cfmodule to give you the attributes of the custom tag that you have defined.

I shall look into this as a future feature

MD

Comment 24 by Nick posted on 8/19/2006 at 7:56 PM

Ray,

What would you say about referencing request or application variables within the custom tag?

Should all variables used in the custom tag be passed in as attributes?

Nick

Comment 25 by Steve Bryant posted on 8/19/2006 at 10:25 PM

Nick,

I can't speak for Ray, but I would say that using any shared-scope variables from within a custom tag is generally bad form as it break encapsulation.

If you pass them in as attributes, of course, that is OK.

You will find some exceptions. For example, I sometimes use request variables to set defaults for attributes. I do make sure that my custom tags work if none of the request variables exist. I also make sure to name the request variables such that it is unlikely to cause a name conflict (I name put the variables in a structure named for the custom tag).

Comment 26 by Nick posted on 8/19/2006 at 11:28 PM

Hi Steve,

Thanks for the comments... I typically do the same thing. I like to make sure all variables referenced within the tag are declared and in the attributes scope -- but sometimes will use request variables as defaults.

I'm curious as to what some others think about this and whether it's considered good practice or not.

Nick

Comment 27 by John Farrar posted on 8/20/2006 at 12:29 AM

Ray... if you use cfimport and reference the root directory of your site as your base it works great! (You can of course also put an application.cfm in the directory with your custom tags to keep malicious security hazards away.) What you get is a directory like "shared" off the root that houses your custom tags in a nested directory.

/shared/tags/security
/shared/tags/forms

<cfimport ...>

Then your code is no problem. (The benefit of easy to read code compared to CFModule is worth it. You also don't run into conflicts where the extra attributes of CFModule get in the way of your custom tag attributes. Lastly, it works perfect with shared hosting!)

My hope is that they allow us to map some of these things in the next version of CF. Then we can map the tags in our application page, and you and I won't have to do it page by page. We will see.

Comment 28 by Raymond Camden posted on 8/20/2006 at 4:22 AM

I still don't like cfimport. Period. :)

Comment 29 by Raymond Camden posted on 8/20/2006 at 4:25 AM

I concur with Steve. You shouldn't break encapsulation when it comes to custom tags... but I've done it myself every now and then. For example with DSNs.

Comment 30 by Javier Julio posted on 8/21/2006 at 11:15 PM

Finally you are posting about custom tags! Today is my lucky day then because I've been meaning to ask you this question for awhile now Ray but first you should be punished for not using cfimport. ;) I find CJ's CF Best Practices on easycfm as a great set to follow. One that I'm very vocal about is to always scope your variables. Is it necessary to scope your variables in custom tags?? By variables I mean regular variables that should only exist in that custom tag, meaning should I just do:

<cfset myName = "Javier Julio">

Or

<cfset Variables.myName = "Javier Julio">

Is there any benefit with either approach?? Or is it more of unneccessary in a custom tag as maybe a custom tag only defaults to the Variables scope whenever you set a simple var?? A great post with some real useful tips. Keep it up!

Comment 31 by Raymond Camden posted on 8/22/2006 at 12:08 AM

I would say no, you do not need to variable scope your variables inside a custom tag.

As for your notice of me doing a post on CTs - I was a huge fan of CTs for many years. I truly do love em. One of the changes to CFLib will be to support CTs, since the Macromedia Exchange has lots of commercial stuff on it.

Comment 32 by Javier Julio posted on 8/22/2006 at 12:13 AM

Thats a brilliant idea Ray as I don't dig a lot of the commercial stuff on the MMExchange so it would be great to see cflib support custom tags as well. If you need contributions I will have several for you. One of them being by own version of your data table and column tags. With the neat getMetaData() function thinking about using it to determine column datatypes so you don't have to specify it.

Comment 33 by Carry posted on 9/25/2006 at 10:42 PM

What's up with using CFPARAM within a custom tag?

Never saw this anywhere else, but I just ran across this tip in the CFMX7 Documentation:

"Tip: To improve performance, avoid using the cfparam tag in ColdFusion functions, including in CFC methods. Instead, place the cfparam tags in the body of the CFML pages."

No problem, I'd never use CFPARAM in a function. But what about custom tags? When this tip says "place the cfparam tags in the body of the CFML pages" is it just referring to simple CFML pages that display output?

I have a custom tag that performs some data validation. I send in the form scope as an attribute collection. Within the body of the custom tag, some of the validation is implemented with CFPARAM.

This tip concerning functions now has me second-guessing that usage. What's the truth concerning perfomance and using CFPARAM within a custom tag?

Thanks!

Comment 34 by Raymond Camden posted on 9/25/2006 at 10:45 PM

I haven't done speed tests on cfparam versus a cfif block. To be honest I don't think most (not all!) speed tests are really worth your time.

That being said - I personally don't think there is anything wrong with it - however - I tend to NOT like it when the default value is complex, like a struct:

cfparam name="foo" default="#structnew()#"

The reason is that CF has to run the structNew even if foo already exists. Again though, that should be a very minor speed hit.

Comment 35 by Carry posted on 9/25/2006 at 10:51 PM

Wow! Expert advice in real time!

I always confuse myself when I read too much.

Thank you :^)

Comment 36 by Raymond Camden posted on 9/25/2006 at 10:56 PM

Remember that my opinion may not be shared by others - especially the "don't worry about speed" comment (which, to be clear, I'm saying to not worry at a very low level). Anyway - just warning you that you may see a bunch of folks chiming in to say I'm wrong. ;)

Comment 37 by praman posted on 10/3/2006 at 10:45 AM

Hi,

Could any body confirm whether using <cfmodule> will physically include the whole file in to the parent file.

Thanks

Comment 38 by Raymond Camden posted on 10/8/2006 at 6:35 PM

"Include" is the wrong word. The entire file is used - but it isn't "included" as the code has it's own variable space. Therefore it is NOT the same as a cfinclude call.

Comment 39 by Russ Michaels posted on 11/2/2007 at 3:22 AM

In general CFC's are actually not faster than custom tags, they are slower.
The only way a CFC is faster is if you have cached it in a persistent scope, such as application scope so that it remains in memory. Or if you are calling multiple methods on that CFC after it has instantiated within the same request, then it may turn out to be quicker than calling the same custom tag the same number of times.
The slowness of CFC's is caused by the initial instantiation of it, so this is where you need to calculate if any improvements are gained if you are not goign to cache the CFC.

So to be clear.

<cfinvoke component="foo"...>
is slower than
<cf_foo...>

but

<cfinvoke component="#application.foo#"...>
would be faster.

Comment 40 by Raymond Camden posted on 11/2/2007 at 4:50 AM

I'm not so sure that is true in CF8, where CFC creation was improved dramatically.

Frankly - you (developer) need to make the choice between CFC versus custom tag based on what you are doing - not which one is 0.001% faster.

Comment 41 by Russ Michaels posted on 11/2/2007 at 5:20 AM

Yes I have heard that about CF8 too, but I have not yet tested it. I would hope it is true because it would certainly make things a lot easier on our hosting servers which are full of badly written code :-)

Comment 42 by Arowolo M.A posted on 4/20/2008 at 4:47 AM

at first i didn't really like using cfimport, but it was the only clean option available

Comment 43 by Richard posted on 9/9/2008 at 3:34 PM

Hi Ray,

I am not sure whether I am missing something but have you posted the link to the Custom tags guide? I would grateful if you can guide me to where it is.

Thanks

Comment 44 by Raymond Camden posted on 9/9/2008 at 5:17 PM

Eh? What guide?

Comment 45 by Frank posted on 7/16/2010 at 12:01 AM

Typo: line reads "<cfexit method="exitTag"%gt;" where it should read "<cfexit method="exitTag">". In case this comment processor does something unexpected, the line ends with the entity & GT ; rather than the right angle character.

Comment 46 by Raymond Camden posted on 7/16/2010 at 12:04 AM

Fixed. Thanks.

Comment 47 by Greg posted on 8/26/2010 at 1:15 AM

Here we are in August 2010, a full 4 years after this article came into being and I wonder what everyone's opinions are now for using CFCs, UDFs, and Custom Tags.

I have seen much that talks about encapsulation and separation of logic/data and display/html. I have seen people advocate using CFCs and UDFs for data only and others to display content as well.

What i want to know is does anyone have a reason that the following is a less than optimal choice in using these options:

1. CFC instantiated in application scope which holds small core functions that are used on 99% of all pages of the site (none of which include any display and are purely data get/set) which also holds core set of variables specific to this application for use on any/all pages (like dsn).

2. Additional CFCs for objects in the application which hold functions specific to the object and/or data specific to the object.

3. Custom Tags for display code that is used frequently like table display, widgets, etc.

4. Included UDF library (is this even needed with the use of the others? if so, when or why? )

Thanks in advance -- i an eager to read everyone's take on this in the here and now.

Comment 48 by John Farrar posted on 8/26/2010 at 4:04 PM

To start off let me say that I have created a framework that does much of what you describe, a couple of frameworks in fact. When we code on the web our "MVC" is actually what is called Model-2. We have an application framework that works as a 'front controller' for all connections to the site. It delegates control of the request to a request controller. In nearly every framework out there this means CFCs acting as controllers and providing an API for interacting with the application framework.

Now about your mixing tags with CFCs question. Take a look at our COOP framework. This is primarily a coding methdology and we are in beta getting closer to release. We are working on our documentation and will be releasing another beta soon when we complete basic tests for these tags. Here is the docs. http://code.google.com/p/cf...

I will also be doing a session at BFlex/BFusion on Custom AJAX tags.

Comment 49 by Raymond Camden posted on 8/26/2010 at 7:03 PM

In general, I only use CFCs for data operations. For layout stuff I'll use custom tags. UDFs are rarely used. I do normally have a set of methods that don't fit in my model and are just generic utilities. For example, I may have a UDF for displayDateTime (to wrap up dateFormat and timeFormat calls into one). In cases like that, I'll create a generic "util" CFC and stuff it in there.

Comment 50 by todd sharp posted on 8/26/2010 at 7:11 PM

What Ray said. Seriously - that's the same thing I do.

Comment 51 by Josh Curtiss posted on 8/26/2010 at 7:18 PM

I'll always use custom tags for layout and HTML output.

I'm a fan of "util" CFCs too. A couple advantages: (1) It makes it clean and easy to use those same methods in a legitimate CFC -- just inject the util CFC in! (2) Sometimes I have functions that may need some configuration. I can have the config data passed into the util CFC once, and it's a clean approach to that issue. (3) It's a common way the Java community handles it, so you're familiarizing yourself with an approach that is common in other circles.

If I'm writing something quick and dirty, throwing a couple UDFs in there, old-school like, is not beyond me. :-) But typically that's short scripts that I'm just throwing together in an hour or two.

Comment 52 by Steini Jonsson posted on 8/26/2010 at 7:26 PM

What Todd said :)

Comment 53 by Greg posted on 8/27/2010 at 5:18 PM

Thank you very much to John, Ray, Todd, Josh, and Steini who chimed in! I really appreciate your having taken the time to answer my post. You have confirmed my thoughts on the matter, and we are proceeding in that direction.

Comment 54 by Ati posted on 7/19/2012 at 6:13 AM

<cfparam name="attributes.result" default="result" type="variableName">
<cfset caller[attribute.result] = now()>

BEST code snippet ever...

(ps I believe it should be you are missing a trailing "s" with attribute.result in the last line.)

Comment 55 by Raymond Camden posted on 7/19/2012 at 6:21 AM

Thanks Ati - corrected.

Comment 56 by Charles Robertson posted on 9/13/2017 at 11:17 AM

Ray. What scope can I use for local variables inside a custom tag. Rather than the attributes scope, which is generally used as an input scope, could I use <cfset local="StructNew()">

Comment 57 (In reply to #56) by Raymond Camden posted on 9/13/2017 at 1:50 PM

In a custom tag, the variables scope is local to it, so you can just do x=1 or variables.x=1 to keep it scoped to the custom tag.

Comment 58 by Charles Robertson posted on 9/13/2017 at 3:02 PM

Thanks Ray. Thats exactly what I wanted to know!