LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 1221 min read

JSTL Core Tags

Learn the JSTL core tag library - c:if, c:forEach, and c:choose/c:when/c:otherwise - and how to add the JSTL taglib to a page.

Introduction

Expression Language, from the previous lesson, is excellent at reading and displaying a single value, but it deliberately cannot express control flow like "if this, show that" or "repeat this for every item in a list". That is exactly the gap JSTL Core Tags fill. Combined with EL, JSTL Core Tags let you write conditionals and loops entirely in tag syntax - no Java scriptlets required at all.

What Is JSTL?

JSTL (JSP Standard Tag Library) is a collection of custom tag libraries that ship as a standard extension to JSP, providing tags for common tasks: conditionals, loops, formatting numbers and dates, working with XML, and executing SQL. This lesson focuses on the Core library, by far the most frequently used, which provides general-purpose control-flow and variable tags.

JSTL LibraryPrefix (convention)Purpose
CorecConditionals, loops, variables, URL handling
FormattingfmtFormatting numbers, dates, and internationalized text
FunctionsfnString utility functions usable inside EL expressions
XMLxProcessing XML documents (less commonly used today)
SQLsqlBasic database queries directly in a page (rarely recommended in production)

Adding the JSTL Taglib

As you saw in the directives lesson, using any tag library requires a taglib directive at the top of the page. For JSTL Core, the convention is the prefix c.

Declaring the JSTL core taglib
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
JSTL Must Be on the Classpath

The taglib directive tells the page which library to use, but the actual JSTL implementation JAR files must also be present in WEB-INF/lib (as covered in Lesson 5) - otherwise the container cannot find the tag library and the page will fail to translate.

c:if

The <c:if> tag conditionally renders its body based on a test attribute, which is typically an EL boolean expression. Unlike Java's if statement, JSTL Core has no built-in c:else tag - for that you need c:choose, covered further below.

Using c:if
<c:if test="${empty username}">
<p>Please log in to continue.</p>
</c:if>
<c:if test="${cartTotal > 100}">
<p>You qualify for free shipping!</p>
</c:if>
Rendered when username is empty and cartTotal is 150

Click Run to see what this code prints.

c:forEach

The <c:forEach> tag loops over a collection (List, array, Map) or a numeric range, making it the JSTL replacement for a Java for loop. The items attribute supplies the collection to iterate, and var names the loop variable used inside the body.

A Servlet setting a List of products as a request attribute
List<String> products = Arrays.asList("Keyboard", "Mouse", "Monitor");
request.setAttribute("products", products);
request.getRequestDispatcher("/products.jsp").forward(request, response);
Looping with c:forEach
<ul>
<c:forEach var="product" items="${products}">
<li>${product}</li>
</c:forEach>
</ul>
Rendered HTML

Click Run to see what this code prints.

c:forEach also supports numeric ranges using begin, end, and step attributes, and it exposes loop status information (like index and count) through the varStatus attribute.

A numeric range with loop status
<c:forEach var="i" begin="1" end="5" varStatus="status">
<p>Item #${status.count}: value is ${i}</p>
</c:forEach>
Rendered HTML

Click Run to see what this code prints.

c:choose, c:when, c:otherwise

For if/else-if/else style branching, JSTL Core provides <c:choose> as a container, with one or more <c:when> tags for each condition and an optional <c:otherwise> as the fallback - directly analogous to a Java switch or if/else-if chain.

Branching with c:choose
<c:choose>
<c:when test="${score >= 90}">
<p>Grade: A</p>
</c:when>
<c:when test="${score >= 75}">
<p>Grade: B</p>
</c:when>
<c:when test="${score >= 60}">
<p>Grade: C</p>
</c:when>
<c:otherwise>
<p>Grade: F</p>
</c:otherwise>
</c:choose>
Rendered when score is 82

Click Run to see what this code prints.

Only the first matching <c:when> branch is rendered - just like Java's if/else-if, evaluation stops at the first true condition, and <c:otherwise> only runs if none of the c:when tags matched.

Other Useful Core Tags

The Core library includes a few more tags worth knowing about, even though c:if, c:forEach, and c:choose cover the majority of everyday needs.

  • c:set - declares a variable at a given scope, e.g. <c:set var="pageTitle" value="Dashboard" scope="request" />
  • c:remove - removes a variable from a given scope.
  • c:out - safely prints a value as text, HTML-escaping it by default to help prevent cross-site scripting (XSS).
  • c:url - builds a properly encoded URL, optionally including query parameters.
c:set and c:out together
<c:set var="greeting" value="Hello, ${username}!" scope="page" />
<p><c:out value="${greeting}" /></p>

Common Mistakes

Avoid These Mistakes
  • Expecting a c:else tag to exist - JSTL Core has no such tag; use c:choose/c:when/c:otherwise instead.
  • Forgetting the taglib directive before using any c: tag, which causes the tags to render as literal, unprocessed text.
  • Placing complex Java logic inside the test attribute instead of a clean EL boolean expression.
  • Not including the JSTL JAR files in WEB-INF/lib, causing a translation-time "tag library not found" error.

Best Practices

  • Use JSTL Core together with EL as the default way to write JSP logic - reserve scriptlets for legacy maintenance only.
  • Use varStatus in c:forEach when you need the current index, count, or first/last flags instead of tracking them manually.
  • Prefer c:out over raw EL output when displaying user-supplied data, since it HTML-escapes by default and helps prevent XSS.
  • Keep the JSTL prefix consistent (c for core) across your entire project to reduce confusion when reading pages.

Frequently Asked Questions

No, they work together. EL supplies the expressions (like ${score >= 90}), while JSTL provides the tags (like c:if, c:forEach) that use those expressions for control flow.

No. JSTL Core intentionally has no c:else tag. For if/else logic, use c:choose with one or more c:when tags and an optional c:otherwise as the fallback.

Yes. When iterating a Map, the loop variable exposes .key and .value properties for each entry, for example ${entry.key} and ${entry.value}.

c:out HTML-escapes its output by default, which helps prevent cross-site scripting (XSS) when displaying data that originally came from user input.

Key Takeaways

  • JSTL is a standard tag library that provides control-flow and utility tags for JSP pages.
  • The Core library (prefix c) is the most used, covering conditionals, loops, and variables.
  • c:if handles single conditions; c:choose/c:when/c:otherwise handles if/else-if/else branching.
  • c:forEach loops over collections or numeric ranges, with optional index/count tracking via varStatus.
  • JSTL Core plus EL together let you write JSP pages with essentially no Java scriptlets at all.

Summary

JSTL Core Tags complete the modern JSP toolkit: EL reads data, and JSTL Core controls flow, together replacing the scriptlet-heavy style from early JSP with clean, readable tag-based syntax. This wraps up the foundational half of the JSP course. Next, you will build on JSTL by exploring its Formatting and Functions tag libraries for working with numbers, dates, and strings.

Next Lesson →

JSTL Formatting & Functions Tags