Reusing Views: Includes & Tag Files
Reusing Views: Includes & Tag Files
Every production JSP application faces a familiar problem: headers, footers, navigation bars, and sidebar widgets need to appear on dozens of pages — and keeping them consistent means centralising them. JSP provides three distinct mechanisms for this: the static include directive, the dynamic <jsp:include> action, and the more powerful custom tag file. Choosing the right mechanism for each situation is part of writing maintainable view code.
Static Include: The include Directive
The static include directive is resolved at translation time — when the JSP container compiles your page into a servlet. The included file's content is literally pasted into the generated Java source before compilation. Because of this, the included file can reference page-scope variables declared in the including page.
.jspf extension to signal they are not standalone pages. Placing them under /WEB-INF/ prevents browsers from accessing them directly, which is considered best practice.
Because the include is resolved at compile time, if you update header.jspf you must force a recompile of every page that includes it. In development servers this usually happens automatically, but it is worth being aware of in environments with aggressive class caching.
Dynamic Include: <jsp:include>
The <jsp:include> action is resolved at request time. Each time the page is served, a sub-request is dispatched to the included resource, and its output is merged into the parent page's response stream. This means the included page runs as an independent unit — it cannot see the parent's page-scope variables, but it can accept parameters and it can be a fully dynamic resource (even a servlet).
The key trade-off: dynamic includes are more flexible and always reflect the latest state of the included file without recompiling the parent, but they carry the overhead of a sub-dispatch per request.
Choosing Between Static and Dynamic Include
- Use static (
includedirective) for truly constant fragments — copyright footers, static navigation that never changes at runtime, shared taglib declarations. Compile-time merging means zero runtime overhead. - Use dynamic (
<jsp:include>) when the fragment needs its own independent scope, when you need to pass parameters, or when the fragment output varies per-request (e.g., a "currently logged-in user" widget).
taglibs.jspf file containing all your <%@ taglib ... %> declarations and statically include it at the top of every page. Because it is a static include, the declarations become part of each page at compile time — no duplication, one place to add or remove a library.
Custom Tag Files
Static and dynamic includes give you reuse at the page fragment level. Tag files take this further: they let you define a custom JSP tag with named attributes, making your markup expressive and self-documenting. A tag file is a plain .tag file (or .tagx for XML syntax) stored in /WEB-INF/tags/ — no Java, no TLD descriptor required.
Suppose you have a "card" component repeated throughout your app. Define it once:
Use it from any JSP by declaring the taglib prefix that points to your tags directory:
<jsp:doBody /> is the tag file equivalent of a slot or yield — it renders whatever content the caller placed between the opening and closing tag. Omit it from your tag file and the body will be silently discarded.
Tag File Attributes in Depth
The <%@ attribute %> directive mirrors a method parameter. Its key options are:
name— the attribute name used in the calling markup.required—trueorfalse; the container will reject the page at translation time if a required attribute is missing.rtexprvalue—trueallows EL expressions (${...}) as the value;falserestricts it to a literal string.type— the Java type of the attribute (e.g.,java.lang.Integer); the container performs automatic string conversion.
Building a Layout Template with Tag Files
One of the most powerful patterns with tag files is a full page layout template — a single tag that wraps every page with a consistent shell, allowing child pages to inject their title and body.
Individual pages become lean and focused:
Summary
Three tools, three use cases: the static include directive merges content at compile time with no runtime cost, perfect for shared taglib declarations and unchanging fragments; <jsp:include> dispatches a sub-request at runtime, giving each fragment its own scope and allowing parameter passing; tag files elevate reuse to a component model — named attributes, body slots, and full JSTL support in a plain .tag file. Together they give you everything you need to build a consistent, maintainable view layer without duplicating a single line of layout markup.