Strongly-typed HTML/CSS/JS component model for Java β the heart of JWebMP.
The core defines the HTML language in Java β every HTML element, CSS property, event, and feature is a first-class Java object using CRTP generics. It generates the HTML, JavaScript, and CSS required for any page, and provides the SPI contracts that allow a mass ecosystem of plugins to be created that adhere to the component model.
Every component serves dual purposes:
toString(true)renders the component as HTML (with all queued CSS/JS) β use this for server-side rendering, template generation, or serving pages on the Vert.x routertoString()renders the component as JSON β use this for AJAX responses, API payloads, or any scenario where the component tree needs to be serialized
Pages can optionally be annotated with @PageConfiguration and served directly via the Vert.x HTTP server, or components can be used standalone to generate HTML/JSON without a server at all.
Provides Page, the full HTML element library (Div, Span, Table, Form, β¦), a typed CSS builder, 50+ server-driven event adapters, page configurators that inject scripts/styles before render, and a Jackson-serialized AJAX pipeline for live DOM updates. Extension is SPI-driven via ServiceLoader.
Built on JWebMP Client Β· GuicedEE Β· Vert.x 5 Β· JPMS module com.jwebmp.core Β· Java 25+
<dependency>
<groupId>com.jwebmp.core</groupId>
<artifactId>core</artifactId>
</dependency>Gradle (Kotlin DSL)
implementation("com.jwebmp.core:jwebmp-core:2.0.0-RC1")Version is managed by the JWebMP BOM.
- HTML language in Java β the core defines the entire HTML5 element set as typed Java classes, along with CSS and JavaScript rendering rules, forming the foundation that all JWebMP plugins build on top of
- Dual rendering modes β
toString(true)produces full HTML with all CSS/JS assets;toString()produces JSON for AJAX/API consumption β same component tree, two output formats - Complete HTML element library β every HTML5 element (
Div,Span,Table,Form,Input,Select,Canvas,Video,Article,Section, β¦) is a typed Java class with CRTP fluent API; child constraints are enforced at compile time - Typed input elements β
InputTextType,InputEmailType,InputNumberType,InputDateType,InputFileType,InputCheckBoxType,InputRadioType, and 15 more β each with the correct HTML attributes - Typed CSS builder β annotation-driven CSS properties (
@CSS) across 14 sub-packages: backgrounds, borders, colours, fonts, margins, padding, displays, lists, tables, text, outline, measurement, height/width, image β rendered inline or composed viaCSSPropertiesFactory - 50+ server-driven event adapters β
OnClickAdapter,OnChangeAdapter,OnSubmitAdapter,OnDragAdapter,OnKeyDownAdapter,OnMouseEnterAdapter, and many more β each backed by aServiceLoaderSPI (IOnClickService,IOnChangeService, etc.). Events must be their own named classes β anonymous inner classes and lambdas are not supported because the framework relies on class identity for serialization andServiceLoaderdiscovery - Page configurators (optional) β
IPageConfiguratorSPI is an optional hook that modifies pages before rendering β use it to inject CSS links, JavaScript references, dynamic scripts, or top-shelf scripts in priority order; pages work perfectly fine without any configurators - Render-ordering hooks β
RenderBeforeLinks,RenderAfterLinks,RenderBeforeScripts,RenderAfterScripts,RenderBeforeDynamicScripts,RenderAfterDynamicScriptsβ fine-grained control over asset insertion - AJAX pipeline β
AjaxCall/AjaxResponse(from jwebmp-client) carry event payloads and DOM update instructions;Eventbase class wires server handlers to browser events - Feature system β
Feature<O, J>wraps a JavaScript library with typed options (JavaScriptPart), CSS/JS references, and automatic dependency ordering. Features must be their own named classes β the framework uses class identity for deduplication, dependency ordering, and Jackson serialization - CSSComponent β render-only CSS classes (no HTML tag) for reusable style-only components
- DataAdapter β bridges server-side data into raw JSON for component consumption
- Content Security Policy β
ContentSecurityPolicybuilder for CSP headers - Jackson module β
JWebMPJacksonModuleregisters custom event deserializers at pre-startup - Component hierarchy β 11-layer deep CRTP chain:
ComponentBaseβComponentHierarchyBaseβComponentHTMLBaseβComponentHTMLAttributeBaseβComponentHTMLOptionsBaseβComponentStyleBaseβComponentThemeBaseβComponentDataBindingBaseβComponentDependencyBaseβComponentFeatureBaseβComponentEventBaseβComponentβ your subclass - Utility belt β
GUIDGenerator,ColourUtils,TextUtilities,EscapeChars,DateUtils, regex patterns (email, date, text)
No server needed β just create components and render:
Page<?> page = new Page<>();
Div<?, ?, ?> container = new Div<>();
container.add(new Paragraph<>().setText("Welcome to JWebMP"));
page.getBody().add(container);
String html = page.toString(true); // full HTML + queued CSS/JS
String json = page.toString(); // JSON representation of the component treeAnnotate with @PageConfiguration to host the page on the Vert.x HTTP server β this is optional and only needed when you want server-side rendering via Vert.x:
@PageConfiguration(url = "/")
public class HomePage extends Page<HomePage> {
public HomePage() {
getBody().add(new H1<>().setText("Hello from JWebMP"));
getBody().add(new Paragraph<>().setText("Server-rendered, type-safe HTML."));
}
}module my.app {
requires com.jwebmp.core;
provides com.jwebmp.core.services.IPage
with my.app.HomePage;
}Boot GuicedEE β the page is now live:
IGuiceContext.instance().inject();
// Vert.x HTTP server starts, HomePage served at "/"Events must be their own named classes β define a top-level or static inner class:
public class ButtonClickEvent extends OnClickAdapter {
public ButtonClickEvent(Component component) {
super(component);
}
@Override
public void onClick(AjaxCall<?> call, AjaxResponse<?> response) {
response.addComponent(new Paragraph<>().setText("Clicked!"));
}
}Then attach it to any component:
Div<?, ?, ?> button = new Div<>();
button.setText("Click me");
button.addEvent(new ButtonClickEvent(button));
page.getBody().add(button);
β οΈ Anonymous inner classes and lambdas are not supported for events or features. The framework relies on class identity for serialization,ServiceLoaderdiscovery, and deduplication. Always create a named class.
public class TooltipFeature extends Feature<TooltipOptions, TooltipFeature> {
public TooltipFeature(IComponentHierarchyBase<?, ?> component) {
super("tooltip", component);
getOptions().setPlacement("top");
}
@Override
protected void assignFunctionalityToComponent() {
addQuery(getComponent().asBase().getJQueryID() + "tooltip(" + getOptions() + ");");
}
}Div<?, ?, ?> styled = new Div<>();
styled.getCss()
.getBackground().setBackgroundColor$(ColourNames.AliceBlue);
styled.getCss()
.getBorder().setBorderWidth(new MeasurementCSSImpl(1, MeasurementTypes.Pixels));
styled.getCss()
.getFont().setFontSize(new MeasurementCSSImpl(14, MeasurementTypes.Pixels));IGuiceContext.instance().inject()
ββ JWebMPPreStartup (IGuicePreStartup, sortOrder=15)
ββ Register JWebMPJacksonModule with ObjectMapper
HTTP request arrives at @PageConfiguration URL
ββ IPage instance created (via Guice binding β Page.class)
ββ IPageConfigurator chain (sorted by sortOrder)
ββ CSSLinksInsertPageConfigurator
β ββ RenderBeforeLinks SPIs
β ββ CSS <link> tags inserted into <head>
β ββ RenderAfterLinks SPIs
ββ ScriptsInsertPageConfigurator
β ββ RenderBeforeScripts SPIs
β ββ <script> tags inserted (by RequirementsPriority)
β ββ RenderAfterScripts SPIs
ββ TopShelfScriptsInsertPageConfigurator
β ββ High-priority scripts in <head>
ββ ScriptsDynamicPageConfigurator
ββ RenderBeforeDynamicScripts SPIs
ββ Inline/dynamic <script> blocks
ββ RenderAfterDynamicScripts SPIs
ββ page.toString(true) β full HTML response
All SPIs are discovered via ServiceLoader. Register implementations with JPMS provides...with or META-INF/services.
Provide a page implementation β typically by subclassing Page:
@PageConfiguration(url = "/dashboard")
public class Dashboard extends Page<Dashboard> {
public Dashboard() {
getBody().add(new H1<>().setText("Dashboard"));
}
@Override
public AjaxResponse<?> onConnect(AjaxCall<?> call, AjaxResponse<?> response) {
// handle initial connection
return response;
}
}Configure pages before rendering β inject CSS, JS, meta tags, or transform the component tree:
public class AnalyticsConfigurator
implements IPageConfigurator<AnalyticsConfigurator> {
@Override
public IPage<?> configure(IPage<?> page) {
page.addJavaScriptReference(new JavascriptReference("analytics", 1.0, "analytics.js"));
return page;
}
@Override
public Integer sortOrder() {
return 500; // after core configurators
}
}Transform any Event after creation β add global behaviour to all events:
public class EventLogger implements IEventConfigurator<EventLogger> {
@Override
public Event<?, ?> configureEvent(Event<?, ?> event) {
// add logging, metrics, or security checks
return event;
}
}| SPI | Purpose |
|---|---|
RenderBeforeLinks |
Insert content before CSS <link> tags |
RenderAfterLinks |
Insert content after CSS <link> tags |
RenderBeforeScripts |
Insert content before <script> tags |
RenderAfterScripts |
Insert content after <script> tags |
RenderBeforeDynamicScripts |
Insert content before dynamic/inline scripts |
RenderAfterDynamicScripts |
Insert content after dynamic/inline scripts |
Each of the 50+ event types has a corresponding service interface discovered via ServiceLoader:
| SPI | Event |
|---|---|
IOnClickService |
Click |
IOnChangeService |
Change |
IOnSubmitService |
Submit |
IOnKeyDownService |
Key down |
IOnMouseEnterService |
Mouse enter |
IOnDragService / IOnDropService |
Drag & drop |
IOnFocusService / IOnBlurService |
Focus / blur |
| β¦ and 40+ more | See com.jwebmp.core.events.services |
The CRTP component chain provides progressive enhancement β each layer adds a capability:
ComponentBase β ID, name, properties, JSON serialization
ββ ComponentHierarchyBase β parent/child tree, add(), CSS/JS references
ββ ComponentHTMLBase β tag rendering, text, raw HTML, newlines
ββ ComponentHTMLAttributeBase β HTML attributes (typed enums)
ββ ComponentHTMLOptionsBase β JavaScript options (JavaScriptPart)
ββ ComponentStyleBase β inline CSS via the CSS builder
ββ ComponentThemeBase β theme support
ββ ComponentDataBindingBase β data-bind hooks
ββ ComponentDependencyBase β CSS/JS dependency refs
ββ ComponentFeatureBase β Feature attachment
ββ ComponentEventBase β Event attachment
ββ Component β final user-facing base
Concrete HTML elements (Div, Table, Form, etc.) extend Component and lock down child/attribute/event types via generics.
Note: The hierarchy depth is a design-time concern only. Modern JDK versions flatten class hierarchies at runtime, so the 11-layer chain has zero performance overhead β you get full type safety with no cost.
| Package | Properties |
|---|---|
css.backgrounds |
background-color, background-image, background-repeat, β¦ |
css.borders |
border-width, border-style, border-color, border-radius, β¦ |
css.colours |
Named colours, colour enumeration |
css.fonts |
font-family, font-size, font-weight, font-style, β¦ |
css.margins |
margin-top, margin-right, margin-bottom, margin-left |
css.padding |
padding-top, padding-right, padding-bottom, padding-left |
css.displays |
display, visibility, overflow, position, float, β¦ |
css.text |
text-align, text-decoration, text-transform, line-height, β¦ |
css.tables |
border-collapse, border-spacing, table-layout, β¦ |
css.lists |
list-style-type, list-style-position, β¦ |
css.outline |
outline-width, outline-style, outline-color |
css.heightwidth |
height, width, min-height, max-width, β¦ |
css.measurement |
MeasurementCSSImpl β px, em, rem, %, vw, vh, β¦ |
css.animatable |
Animatable property markers |
| Variable / Property | Default | Purpose |
|---|---|---|
@PageConfiguration(url=) |
"/" |
URL path for page discovery |
| Environment-driven ports | via jwebmp-vertx | HTTP/HTTPS listen ports |
com.jwebmp.core
βββ com.jwebmp.client (SPI contracts, AjaxCall/Response, interceptors)
βββ com.guicedee.client (DI, lifecycle, CallScope)
βββ com.guicedee.vertx (Vert.x lifecycle, event bus)
βββ com.guicedee.jsonrepresentation (Jackson ObjectMapper, IJsonRepresentation)
βββ io.vertx.core (Vert.x core)
βββ io.vertx.web (Vert.x Web β Router)
βββ com.google.guice (Dependency injection)
βββ com.fasterxml.jackson.databind (JSON serialization)
βββ jakarta.validation (Bean Validation)
βββ org.apache.commons.lang3 (String utilities)
βββ org.apache.commons.text (Text utilities)
βββ org.apache.commons.io (IO utilities)
βββ net.sf.uadetector.core (User-agent parsing)
βββ net.sf.uadetector.resources
Module name: com.jwebmp.core
The module:
- exports
com.jwebmp.core,com.jwebmp.core.base,com.jwebmp.core.base.html,com.jwebmp.core.base.html.inputs,com.jwebmp.core.base.page,com.jwebmp.core.components,com.jwebmp.core.events.*(50+ packages),com.jwebmp.core.htmlbuilder.css.*(14 packages),com.jwebmp.core.utilities,com.jwebmp.core.enumerations,com.jwebmp.core.implementations - provides
IGuiceModulewithJWebMPServicesBindings,IGuicePreStartupwithJWebMPPreStartup,IGuiceScanModuleInclusionswithJWebMPModuleInclusions,IPageConfiguratorwithCSSLinksInsertPageConfigurator,ScriptsInsertPageConfigurator,ScriptsDynamicPageConfigurator,TopShelfScriptsInsertPageConfigurator,IRegularExpressionswith regex pattern providers - uses
IPage,IPageConfigurator,IErrorPage,IEventConfigurator,IDynamicRenderingServlet,IOnComponentConfigured,IOnDataBind,IOnDataBindCloak,IOnComponentHtmlRender,IOnComponentAdded,IAfterRenderComplete, allRenderBefore*/RenderAfter*SPIs, all 50+ event service SPIs
| Class | Role |
|---|---|
Page |
Top-level HTML page β subclass and annotate with @PageConfiguration |
Component |
Base class for all HTML elements β CRTP with typed children, attributes, features, events |
CSSComponent |
CSS-only component (renders as class, no HTML tag) |
Feature |
Wraps a JS library β typed options, CSS/JS references, jQuery integration |
Event |
Server-driven event handler β wires browser events to AjaxCall/AjaxResponse |
DataAdapter |
Bridges server data into raw JSON for component consumption |
ContentSecurityPolicy |
Builder for CSP headers |
PageOptions |
Page-level options (title, author, favicon, keywords, etc.) |
CSSPropertiesFactory |
Renders @CSS-annotated objects into inline CSS strings |
JWebMPServicesBindings |
IGuiceModule β binds IPage, page configurators, render-ordering SPIs |
JWebMPPreStartup |
IGuicePreStartup β registers JWebMPJacksonModule at startup |
JWebMPJacksonModule |
Jackson module β custom Event and IEventTypes deserializers |
IEventConfigurator |
SPI β transform any Event after creation |
GUIDGenerator |
Unique ID generation for components |
| Element | Class | Children type |
|---|---|---|
<div> |
Div |
GlobalChildren |
<span> |
Span |
GlobalChildren |
<p> |
Paragraph |
GlobalChildren |
<h1>β<h6> |
H1βH6 |
GlobalChildren |
<table> |
Table |
TableHeaderGroup, TableBodyGroup, TableFooterGroup |
<form> |
Form |
FormChildren |
<input> |
Input + 22 typed variants |
inline |
<select> |
Select |
Option, OptionGroup |
<ul> / <ol> |
List |
ListItem |
<a> |
Link |
GlobalChildren |
<img> |
Image |
inline |
<button> |
Button |
GlobalChildren |
<header> / <footer> / <nav> / <section> / <article> / <aside> |
Semantic elements | GlobalChildren |
<canvas> / <video> / <audio> |
Media elements | Source, Track |
<script> / <style> / <link> |
Asset elements | β |
# Build
mvn -B -ntp -DskipTests package
# Test
mvn -B -ntp verifyPrerequisites: Java 25+, Maven 3.9+
Issues and pull requests are welcome at github.com/JWebMP/Core/issues.