Rendering API and contracts

Package: io.mindspice.simplypages.core.

API Contract
Component.render(RenderContext) Required render method; returns HTML.
Component.render() Renders with a fresh empty context.
Component.render(Map) Converts values to a context and renders.
Component.compile() Shortcut for Template.of(component).
HtmlTag.withInnerText(String) Escapes text; null becomes empty; clears a text slot.
HtmlTag.withInnerText(SlotKey<String>) Resolves text from the render context.
HtmlTag.withUnsafeHtml(String) Inserts trusted HTML and clears the previous text slot.
HtmlTag.withAttribute(name, value) Replaces the same name case-insensitively; encodes the value.
HtmlTag.withId(null) Removes the ID.
HtmlTag.addStyle(property, value) Replaces the exact CSS property; rejects declaration breakout.
HtmlTag.addTrustedStyle(property, value) Accepts trusted advanced CSS values; still validates the property name.
Module.build() Lazy and idempotent after success. Failed builds restore child/attribute collections before retry.
Module.withWidth/withMinWidth/withMaxWidth Always throw UnsupportedOperationException; size modules through layout.

Tag and attribute names reject malformed markup delimiters. Attribute values that are empty or null render as boolean attributes. Generic attributes do not validate JavaScript, URL schemes, or business policy; attribute escaping does not make those contexts safe.

URL and style method boundaries

Link constructors/create/withHref apply the http/https/mailto/tel/relative policy. Image constructors/factories/withSrc reject javascript and non-image data prefixes, retaining custom/FTP/blob schemes and the existing data:image/ prefix behavior. For classification only, both trim boundary C0/ASCII space, remove TAB/LF/CR and fold ASCII case independently of locale. Normalized supported spellings such as ht<TAB>tp: and data:im<TAB>age/ are accepted. Storage/getters and encoded output keep the original value; there is no entity/percent decoding, Unicode normalization, MIME/payload inspection or destination authorization. Rejected typed setters leave prior state unchanged.

Generic href/src replacement bypasses those validators and need not update their getters. HTMX endpoints, Dropdown/AccountWidget/nav entries (including nested constructors/utility links), top/side builder links and aliases, Hero CTAs, Card/Gallery images, Audio/Video sources/posters and Form/FormModule destinations remain application-controlled or separately validated for their actual context. AccountBar's link conveniences already construct Link; Banner's generated ordinary horizontal image constructs Image at build. Neither delegates CSS backgrounds or dynamic endpoints to those policies.

addStyle supplies property-name/declaration-breakout checks, not semantic CSS/URL policy. addTrustedStyle bypasses value-breakout checks; Style.addInlineStyle and raw style attributes retain separators. Banner/Hero CSS background URLs need control of single-quoted url() syntax, not merely Image validation. Their colors, AccountBar background color, Spacer.custom and ProgressBar.withHeight are raw style assembly. Supply application-controlled or separately CSS-context-validated inputs; width helpers' restricted token grammar is a different contract. Compilation adds no URL/CSS checks and standard static snapshots retain the configuration present at compile time.

Keys and values

The SlotKey<T> canonical constructor and all SlotKey.of factories throw NullPointerException immediately for a null name. Every non-null name is preserved literally, including empty and blank strings, without trimming, case folding, or Unicode normalization.

Equality and hash code use the name, not the generic type or default provider. Keep a single declared type for each name; generic typing does not validate differently typed keys that reuse a name. Keys may have fixed defaults or defaults computed from a context. Default providers may be null and are not evaluated during construction.

Slot.of(key) renders components by calling render(context) and escapes other values as text. Missing values render empty unless a default exists. Explicit compiled values are trusted HTML, including when used by a text slot.

Context policy

RenderContext is mutable and not thread-safe. Create one per request.

Operation or policy Effect
put(key, value) Stores a live value; null removes it.
putCompiled(key, html) Stores trusted rendered HTML; null removes it.
remove(key) / clear() Removes one or all entries.
get(key) Returns a live value or key default. A compiled entry falls back to the default, not cached HTML.
getCompiled(key) Returns cached HTML when present.
NEVER_COMPILE Does not create new cached HTML; existing compiled entries still render.
COMPILE_ON_FIRST_HIT Replaces explicitly stored live slot values with their first rendered HTML.

Direct slots, text slots, and template slots honor compiled entries. Defaults are evaluated live and are not automatically persisted. Replacing one input does not invalidate other slots that were compiled using it; use a fresh context when dependencies change.

Template compilation

Standard tags flatten into static strings and dynamic slot segments. Compilation respects getChildrenStream(), including generated options, cards, lists, and table structure. Modules build before compilation. A subclass overriding render(RenderContext) remains a live component delegate so custom wrappers, authorization, and request logic still execute. Other custom components also remain live delegates.

Templates therefore do not deep-copy or freeze arbitrary components. Reuse a template only when its retained delegates are safe to share; use pre-rendered strings for fully immutable static output. Implement custom rendering in render(RenderContext), including propagation to children. Overriding only render() does not affect context-aware parent rendering.

TemplateComponent binds a template to a fixed context and ignores the parent's context. ShellTemplate adds a document doctype and exposes a content slot through contentSlot().

See rendering explanation and the original slot reference.

All reference