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 Library | Prefix (convention) | Purpose |
|---|---|---|
| Core | c | Conditionals, loops, variables, URL handling |
| Formatting | fmt | Formatting numbers, dates, and internationalized text |
| Functions | fn | String utility functions usable inside EL expressions |
| XML | x | Processing XML documents (less commonly used today) |
| SQL | sql | Basic 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.
<%@ page contentType="text/html;charset=UTF-8" %><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>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.
<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>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.
List<String> products = Arrays.asList("Keyboard", "Mouse", "Monitor");request.setAttribute("products", products);request.getRequestDispatcher("/products.jsp").forward(request, response);<ul> <c:forEach var="product" items="${products}"> <li>${product}</li> </c:forEach></ul>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.
<c:forEach var="i" begin="1" end="5" varStatus="status"> <p>Item #${status.count}: value is ${i}</p></c:forEach>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.
<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>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 var="greeting" value="Hello, ${username}!" scope="page" /><p><c:out value="${greeting}" /></p>Common 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.