Custom Tags Basics
Understand what a custom tag library is and get a conceptual, practical overview of building your own simple custom tag.
Introduction
Every <c:forEach> and <fmt:formatDate> you have used so far is itself built on a mechanism available to any JSP developer: custom tags. When JSTL does not cover something specific to your application — say, a tag that renders a formatted price badge, or one that checks a custom permission — you can write your own tag and use it exactly like a built-in one.
- What a custom tag library is made of.
- How a simple tag handler class works.
- How a Tag Library Descriptor (TLD) wires a tag to its handler.
- How to use a custom tag with attributes on a JSP page.
What Is a Custom Tag Library?
A custom tag library bundles two things: one or more Java classes (tag handlers) that contain the logic to run when the tag is encountered, and a Tag Library Descriptor (TLD) file, an XML document that maps a tag name to its handler class. Once packaged, you use the library the same way you used core, fmt, and fn — with a taglib directive.
The Tag Handler Class
The simplest tag handlers extend SimpleTagSupport and override doTag(), writing output through the JSP writer. Here is a tag that prints a friendly greeting.
// GreetTag.javapackage com.programinds.tags;
import jakarta.servlet.jsp.tagext.SimpleTagSupport;import jakarta.servlet.jsp.JspException;import java.io.IOException;
public class GreetTag extends SimpleTagSupport { private String name;
public void setName(String name) { this.name = name; }
@Override public void doTag() throws JspException, IOException { getJspContext().getOut().write("Hello, " + name + "! Welcome to PrograMinds."); }}The Tag Library Descriptor
The TLD tells the container which tag name maps to which class, and what attributes it accepts. It lives under WEB-INF and is packaged with the application.
<!-- WEB-INF/tlds/programinds-tags.tld --><taglib xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="2.1"> <tlib-version>1.0</tlib-version> <short-name>pm</short-name> <uri>http://programinds.com/tags</uri>
<tag> <name>greet</name> <tag-class>com.programinds.tags.GreetTag</tag-class> <body-content>empty</body-content> <attribute> <name>name</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag></taglib>Using the Custom Tag
With the class compiled and the TLD in place, the tag is used exactly like any JSTL tag: declare its prefix, then call it.
<%@ taglib prefix="pm" uri="http://programinds.com/tags" %>
<pm:greet name="Alex" />Click Run to see what this code prints.
Tags with Attributes
Each public setter in the tag handler becomes an attribute the JSP author can pass in, and rtexprvalue="true" in the TLD allows that attribute to be a runtime expression rather than only a fixed string.
<pm:greet name="${sessionScope.username}" />There is nothing magical about <c:forEach> or <fmt:formatDate> — they are tag handler classes and TLD files exactly like the one above, just shipped and maintained by the JSTL project instead of written by you.
Common Mistakes
- Forgetting rtexprvalue="true" in the TLD, which prevents an attribute from accepting an EL expression.
- Placing the TLD file outside WEB-INF, where the container will not discover it.
- Writing heavy business logic directly in a tag handler instead of delegating to a service class.
- Mismatching the setter name in Java with the attribute name declared in the TLD.
Best Practices
- Reach for existing JSTL tags first — write a custom tag only when nothing standard covers the need.
- Keep custom tags focused on presentation, delegating real logic to Java service classes.
- Document each custom tag's attributes clearly, since IDE support is weaker than for standard libraries.
- Group related custom tags into one well-named TLD and URI for your application.
Frequently Asked Questions
No. For simple markup reuse, jsp:include or a JavaBean is often simpler; custom tags shine when you need reusable logic with a clean, tag-like syntax.
Yes, by setting body-content to something other than empty in the TLD and reading the body inside doTag().
No, there is also the older, more complex Tag and BodyTag interfaces, but SimpleTagSupport is the modern, recommended starting point.
Key Takeaways
- A custom tag library pairs Java tag handler classes with a TLD descriptor.
- SimpleTagSupport and doTag() are the modern way to write a tag handler.
- The TLD maps a tag name and its attributes to the handler class.
- JSTL itself is built on exactly this same custom tag mechanism.
Summary
Custom tags round out your toolbox for keeping JSP markup clean and reusable. Next, you will look at what happens when things go wrong — how JSP's errorPage and isErrorPage directives handle exceptions gracefully.