Forum Renderer API Reference
This page summarizes forum renderer APIs and extension points.
Core Entry Points
ForumCategoryRenderer<CATEGORY extends ForumCategoryData, CTX>ForumTopicRenderer<TOPIC extends ForumTopicData, CTX>ForumCommentRenderer<COMMENT extends ForumCommentData, CTX>ForumCollapsibleComposer
Factory:
ForumCategoryRenderer.builder()ForumTopicRenderer.builder()ForumCommentRenderer.builder()
Render methods:
ForumCategoryRenderer.render(Collection<CATEGORY>, CTX)ForumTopicRenderer.render(Collection<TOPIC>, CTX)ForumTopicRenderer.render(Collection<TOPIC>, CTX, TopicPagination)ForumCommentRenderer.render(Collection<COMMENT>, CTX)ForumCommentRenderer.render(Collection<COMMENT>, CTX, CommentPagination)
Required Data Contracts
ForumCategoryData
Required:
id()title()
Optional defaults:
description()topicCount()
ForumTopicData
Required:
id()title()body()
Optional defaults:
author()timestamp()likes()replies()
ForumCommentData
Required:
id()topicId()body()
Optional defaults:
parentId()depth()author()avatarUrl()timestamp()likes()replies()
Final Component Contracts
ForumCategoryComponent
Renderer-populated fluent methods:
withCategoryId(String)withTitle(String)withDescription(String)withTopicCount(Integer)
ForumTopicComponent
Renderer-populated fluent methods:
withTopicId(String)withTitle(String)withTitleLink(ForumTopicTitleLink)(default no-op for custom components)withAuthor(String)withTimestamp(String)withBody(Component)withActions(List<Component>)withLikes(Integer)withReplies(Integer)
ForumCommentComponent
Renderer-populated fluent methods:
withCommentId(String)withTopicId(String)withParentId(String)withDepth(int)withAuthor(String)withAvatarUrl(String)withTimestamp(String)withBody(Component)withActions(List<Component>)withLikes(Integer)withReplies(Integer)
Default comment depth and layout
DefaultForumCommentComponent emits data-depth on every card as the exact configured
signed int, including zero, negative values and integer extremes. It stores the value
unchanged. A single forum-comment-depth-0 through forum-comment-depth-4 class controls
presentation: negative depths look like zero; depths above four look like four.
parentId is independent of depth. Null/blank parents omit data-parent-id; nonblank
values are emitted with attribute escaping.
Framework CSS uses logical-start indentation of 16px per visual level, or 8px at viewport widths up to 920px, additionally limited to 8% of the containing inline size. Cards flow into the remaining width. The default retains its 150x150 avatar reservation, including blank/invalid-URL fallback, and stacks its owned layout in narrow hosts when needed. Depth adds no inline style; ordinary host CSS can override these defaults.
Custom component suppliers receive the raw parent/depth unchanged once per selected item
and own their markup. Raw depth metadata or the common forum-comment class alone does
not opt custom markup into the generated depth styling. Default rendering preserves
configured state and passes the same context to body/actions exactly once. Templates
retain live default/subclass rendering; finish configuration before sharing and keep
contexts and child delegates appropriately owned.
ForumCollapsibleComposer
Factory:
ForumCollapsibleComposer.create(String summaryText, Component content)
Fluent methods:
withSummaryText(String)withContent(Component)withExpanded(boolean)expandedByDefault()withClass(String)
Behavior:
- renders a
<details>wrapper with a<summary>label and composer content region - default state is collapsed (no
openattribute) - use
withExpanded(true)orexpandedByDefault()for edit-in-progress flows
Builder Customization Hooks
Component suppliers:
withCategoryComponentSupplier(Supplier<? extends ForumCategoryComponent>)withTopicComponentSupplier(Supplier<? extends ForumTopicComponent>)withCommentComponentSupplier(Supplier<? extends ForumCommentComponent>)
Topic content/title hooks:
withBodyTextResolver(BiFunction<TOPIC, CTX, String>)withTitleLinkResolver(BiFunction<TOPIC, CTX, ForumTopicTitleLink>)
Actions:
withActionProvider(ForumActionProvider<..., CTX>)on topic/comment renderers
Tags:
withTagParser(ForumTagParser)on topic/comment rendererswithResolverRegistry(ForumTagResolverRegistry)on topic/comment renderers
Pagination HTMX:
- Topic renderer:
withPaginationEndpointResolver(TopicPaginationEndpointResolver)withPaginationHxTarget(String)withPaginationHxSwap(String)withTopicScopeExtractor(Function<TOPIC, String>)
- Comment renderer:
withPaginationEndpointResolver(CommentPaginationEndpointResolver)withPaginationHxTarget(String)withPaginationHxSwap(String)
Action Contracts
ForumActionProvider<SOURCE, CTX>
provide(ForumActionContext<SOURCE, CTX>)none()
ForumActionContext<SOURCE, CTX>
Fields:
itemType(ForumActionType.TOPICorForumActionType.COMMENT)itemIdtopicIdsourcecontext
DefaultForumActionProvider<SOURCE, CTX>
Visibility:
showQuoteWhen(...)showEditWhen(...)showDeleteWhen(...)
Endpoint mappers:
withQuoteEndpoint(...)withEditEndpoint(...)withDeleteEndpoint(...)
Icon overrides:
withQuoteIcon(...)withEditIcon(...)withDeleteIcon(...)
HTMX defaults:
withHxTarget(String)withHxSwap(String)withQuoteHxInclude(String)(quote-action-onlyhx-includeselector)
Pagination Contracts
ForumTopicRenderer.TopicPagination
Fields:
scopeIdpage(1-based)topicsPerPagetotalTopics
Notes:
scopeIdis used for pagination metadata and endpoint generation.- Topic filtering is application-owned by default.
- If
withTopicScopeExtractor(...)is configured, renderer filters to matchingscopeIdbefore page slicing. totalTopicsshould represent all scoped topics (not only current page slice).topicsPerPageis the hard render cap for one response. IftopicsPerPage=8, the renderer outputs at most 8 topic items.topicsPerPagecontrols topic-card count only; it does not control body preview length.- Enabled pagination controls include
data-sp-scroll-top="target"for target-fragment top reset after HTMX swaps.
Helpers:
totalPages()currentPage()hasPrevious()hasNext()
ForumTopicRenderer.TopicPaginationEndpointResolver
endpoint(String scopeId, int page, int topicsPerPage)- default:
/forum/topics?scope={scopeId}&page={page}&size={topicsPerPage}
ForumTopicTitleLink
Fields:
href(required)hxGet(optional)hxTarget(optional)hxSwap(optional)hxPushUrl(optional)
Factories:
ForumTopicTitleLink.href(String href)ForumTopicTitleLink.htmx(String href, String hxGet, String hxTarget, String hxSwap, String hxPushUrl)
ForumCommentRenderer.CommentPagination
Fields:
topicIdpage(1-based)commentsPerPagetotalComments
Notes:
- Without pagination, comments retain flat collection order, including comments from different topics.
- When pagination is supplied, renderer filters incoming comments by
topicIdbefore slicing. - Parent/depth metadata does not reorder or group comments. A child can precede its parent or appear on a different page; missing, self, cyclic and cross-topic parent references are not reconciled or validated. There is no tree DOM or subtree pagination.
totalCommentsshould represent all comments for the topic scope (not only current page slice).commentsPerPageis the hard render cap for one response. IfcommentsPerPage=8, the renderer outputs at most 8 comment items.- Enabled pagination controls include
data-sp-scroll-top="target"for target-fragment top reset after HTMX swaps.
Helpers:
totalPages()currentPage()hasPrevious()hasNext()
ForumCommentRenderer.CommentPaginationEndpointResolver
endpoint(String topicId, int page, int commentsPerPage)- default:
/forum/topics/{topicId}/comments?page={page}&size={commentsPerPage}
Tag Contracts
TagType
- normalized/validated key wrapper
- use
TagType.of("custom.tag")
Tag
- value token (
TagType+ token value)
ForumTagParser
- token syntax:
[[key::value]] - escaped literal token:
\[[key::value]] - malformed tokens are preserved as text
ForumTagResolver
tagType()resolveBatch(Set<Tag>)
ForumTagResolverRegistry
Creation:
create()withBuiltIns()
Registration:
register(ForumTagResolver)registerBuiltIns()
Resolution:
resolve(TagType, Set<Tag>)resolveAll(Map<TagType, Set<Tag>>)hasResolver(TagType)
ForumTagResolvers
of(key, batchResolver)- built-ins:
quote(),image(),mention(),link()
Defaults
- Default final components:
DefaultForumCategoryComponentDefaultForumTopicComponentDefaultForumCommentComponent
- All renderer builders default to these component suppliers.